<commit_before>import Client from "../Client.js";

let changeListeners = [];
let coffees = [];
let processings = [];
let productStatuses =[];

let notifyChange = () => {
  changeListeners.forEach((listener) => {
    listener();
  });
}

let fetchCoffees = () => {

  Client.items()
    .type('coffee')
    .orderParameter('elements.product_name')
    .get()
    .subscribe(response => {
      coffees = response.items;
      notifyChange();
    });
}

let fetchFilterProperties = () => {
  Client
    .type('coffee')
    .get()
    .subscribe(response => {
      processings = response
        .type
        .elements.find(element => element.codename === "processing")
        .options;
    });
let fetchProcessings = () => {
  Client.taxonomy("processing")
    .get()
    .subscribe(response => {
      processings = response.terms;
      notifyChange();
  });
};

let fetchProductStatuses = () => {
    Client.taxonomy("product_status")
      .get()
      .subscribe(response => {
        productStatuses = response.terms;
        notifyChange();
    });
}

export class Filter {
  constructor() {
    this.processings = [];
    this.productStatuses = [];
  }

  matches(coffee) {
    return this.matchesProcessings(coffee) && this.matchesProductStatuses(coffee);
  }

  matchesProcessings(coffee) {
    if (this.processings.length === 0) {
      return true;
    }

    let processings = coffee.elements.processing.value.map(x => x.codename);

    return this.processings.some(x => processings.includes(x));
  }

  matchesProductStatuses(coffee) {
    if (this.productStatuses.length === 0) {
      return true;
    }

    let statuses = coffee.elements.product_status.value.map(x => x.codename);

    return this.productStatuses.some(x => statuses.includes(x));
  }

  toggleProcessing(processing) {
    let index = this.processings.indexOf(processing);

    if (index < 0) this.processings.push(processing); else this.processings.splice(index, 1);
  }

  toggleProductStatus(status) {
    let index = this.productStatuses.indexOf(status);

    if (index < 0) this.productStatuses.push(status); else this.productStatuses.splice(index, 1);
  }
}

let coffeeFilter = new Filter();

class CoffeeStore {

  // Actions

  provideCoffee(coffeeSlug) {
    fetchCoffees();
  }

  provideCoffees() {
    fetchCoffees();
  }

  provideProcessings() {
    fetchProcessings();
  }

  provideProductStatuses() {
    fetchProductStatuses();
  }

  // Methods

  getCoffee(coffeeSlug) {
    return coffees.find((coffee) => coffee.urlPattern.value === coffeeSlug);
  }

  getCoffees() {
    return coffees;
  }

  getProcessings() {
    return processings;
  }

  getProductStatuses() {
    return productStatuses;
  }

  getFilter() {
    return coffeeFilter;
  }

  setFilter(filter) {
    coffeeFilter = filter;
    notifyChange();
  }

  // Listeners

  addChangeListener(listener) {
    changeListeners.push(listener);
  }

  removeChangeListener(listener) {
    changeListeners = changeListeners.filter((element) => {
      return element !== listener;
    });
  }

}

export default new CoffeeStore();
<commit_msg>use sdk taxonomy endpoint in client to create product catalog filter<commit_after>import Client from "../Client.js";

let changeListeners = [];
let coffees = [];
let processings = [];
let productStatuses = [];

let notifyChange = () => {
  changeListeners.forEach((listener) => {
    listener();
  });
}

let fetchCoffees = () => {

  Client.items()
    .type('coffee')
    .orderParameter('elements.product_name')
    .get()
    .subscribe(response => {
      coffees = response.items;
      notifyChange();
    });
}

let fetchProcessings = () => {
  Client.taxonomy("processing")
    .get()
    .subscribe(response => {
      processings = response.terms;
      notifyChange();
    });
};

let fetchProductStatuses = () => {
  Client.taxonomy("product_status")
    .get()
    .subscribe(response => {
      productStatuses = response.terms;
      notifyChange();
    });
}

export class Filter {
  constructor() {
    this.processings = [];
    this.productStatuses = [];
  }

  matches(coffee) {
    return this.matchesProcessings(coffee) && this.matchesProductStatuses(coffee);
  }

  matchesProcessings(coffee) {
    if (this.processings.length === 0) {
      return true;
    }

    let processings = coffee.processing.value.map(x => x.codename);

    return this.processings.some(x => processings.includes(x));
  }

  matchesProductStatuses(coffee) {
    if (this.productStatuses.length === 0) {
      return true;
    }

    let statuses = coffee.productStatus.value.map(x => x.codename);

    return this.productStatuses.some(x => statuses.includes(x));
  }

  toggleProcessing(processing) {
    let index = this.processings.indexOf(processing);

    if (index < 0) this.processings.push(processing); else this.processings.splice(index, 1);
  }

  toggleProductStatus(status) {
    let index = this.productStatuses.indexOf(status);

    if (index < 0) this.productStatuses.push(status); else this.productStatuses.splice(index, 1);
  }
}

let coffeeFilter = new Filter();

class CoffeeStore {

  // Actions

  provideCoffee(coffeeSlug) {
    fetchCoffees();
  }

  provideCoffees() {
    fetchCoffees();
  }

  provideProcessings() {
    fetchProcessings();
  }

  provideProductStatuses() {
    fetchProductStatuses();
  }

  // Methods

  getCoffee(coffeeSlug) {
    return coffees.find((coffee) => coffee.urlPattern.value === coffeeSlug);
  }

  getCoffees() {
    return coffees;
  }

  getProcessings() {
    return processings;
  }

  getProductStatuses() {
    return productStatuses;
  }

  getFilter() {
    return coffeeFilter;
  }

  setFilter(filter) {
    coffeeFilter = filter;
    notifyChange();
  }

  // Listeners

  addChangeListener(listener) {
    changeListeners.push(listener);
  }

  removeChangeListener(listener) {
    changeListeners = changeListeners.filter((element) => {
      return element !== listener;
    });
  }

}

export default new CoffeeStore();
<|endoftext|>


<commit_before>import React, {Component} from 'react';
import PropTypes from 'prop-types';

import Paper from '../Paper';

import './Widget.css';

export default class Widget extends Component {

    constructor(props) {
        super(props);
    }

    render() {

        const {children, className, style, depth} = this.props;

        return (
            <Paper className={`widget ${className}`}
                   style={style}
                   depth={depth}>
                {children}
            </Paper>
        );

    }
};

Widget.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * This number represents the zDepth of the root element shadow.
     */
    depth: PropTypes.number

};

Widget.defaultProps = {

    className: '',
    style: null,

    depth: 1

};<commit_msg>optimze Widget<commit_after>import React, {Component} from 'react';
import PropTypes from 'prop-types';

import Paper from '../Paper';

import './Widget.css';

export default class Widget extends Component {

    constructor(props, ...restArgs) {
        super(props, ...restArgs);
    }

    render() {

        const {children, className, style, depth} = this.props;

        return (
            <Paper className={`widget ${className}`}
                   style={style}
                   depth={depth}>
                {children}
            </Paper>
        );

    }
};

Widget.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * This number represents the zDepth of the root element shadow.
     */
    depth: PropTypes.number

};

Widget.defaultProps = {

    className: '',
    style: null,

    depth: 1

};<|endoftext|>


<commit_before>// @flow
/* eslint-disable import/prefer-default-export */

import * as types from "constants/actionTypes";
import * as optionTypes from "constants/optionTypes";
import { paletteList } from "palettes";
import { THEMES } from "palettes/user";

import type { ColorRGBA, Filter, FilterFunc } from "types";

export const importState = (json: string) => {
  const deserialized = JSON.parse(json);
  return {
    type: types.LOAD_STATE,
    data: deserialized
  };
};

export const setInputVolume = (volume: number) => ({
  type: types.SET_INPUT_VOLUME,
  volume
});

export const setInputPlaybackRate = (rate: number) => ({
  type: types.SET_INPUT_PLAYBACK_RATE,
  rate
});

export const setInputCanvas = (canvas: HTMLCanvasElement) => ({
  type: types.SET_INPUT_CANVAS,
  canvas
});

export const setScalingAlgorithm = (algorithm: string) => ({
  type: types.SET_SCALING_ALGORITHM,
  algorithm
});

export const loadImage = (
  image: HTMLImageElement,
  time: ?number = 0,
  video: ?HTMLVideoElement,
  dispatch: ?any
) => ({
  type: types.LOAD_IMAGE,
  image,
  time,
  video,
  dispatch
});

export const loadImageAsync = (file: File) => (dispatch: Dispatch) => {
  const reader = new FileReader();
  const image = new Image();

  reader.onload = event => {
    image.onload = () => {
      dispatch(loadImage(image, null, null, dispatch));
    };
    image.src = event.target.result;
  };

  reader.readAsDataURL(file);
};

export const loadVideoAsync = (
  file: File,
  volume: number = 1,
  playbackRate: number = 1
) => (dispatch: Dispatch) => {
  const reader = new FileReader();
  const video = document.createElement("video");

  reader.onload = event => {
    const i = new Image();
    const canvas = document.createElement("canvas");
    const ctx = canvas.getContext("2d");

    const loadFrame = () => {
      URL.revokeObjectURL(i.src);

      if (!video.paused && video.src !== "") {
        i.width = video.videoWidth;
        i.height = video.videoHeight;
        ctx.drawImage(video, 0, 0);
        canvas.toBlob(blob => {
          if (blob) {
            i.src = URL.createObjectURL(blob);
            i.onload = () => {
              if (!video.paused && video.src !== "") {
                requestAnimationFrame(loadFrame);
                dispatch(loadImage(i, video.currentTime, video, dispatch));
              }
            };
          }
        });
      }
    };

    let firstPlay = true;
    video.onplaying = () => {
      if (firstPlay) {
        firstPlay = false;
        canvas.width = video.videoWidth;
        canvas.height = video.videoHeight;
        requestAnimationFrame(loadFrame);
      }
    };

    const blob = new Blob([event.target.result]);
    video.volume = volume;
    video.src = URL.createObjectURL(blob);
    video.playbackRate = playbackRate;
    video.loop = true;
    video.autoplay = true;
  };

  reader.readAsArrayBuffer(file);
};

export const loadMediaAsync = (
  file: File,
  volume: number = 1,
  playbackRate: number = 1
) => {
  if (file.type.startsWith("video/")) {
    return loadVideoAsync(file, volume, playbackRate);
  }

  return loadImageAsync(file);
};

export const setConvertGrayscale = (value: boolean) => ({
  type: types.SET_GRAYSCALE,
  value
});

export const selectFilter = (name: string, filter: Filter) => ({
  type: types.SELECT_FILTER,
  name,
  filter
});

export const filterImage = (image: HTMLImageElement) => ({
  type: types.FILTER_IMAGE,
  image
});

export const filterImageAsync = (
  input: HTMLCanvasElement,
  filter: FilterFunc,
  options: ?any
) => (dispatch: Dispatch) => {
  const output = filter(input, options, dispatch);
  if (!output) return { type: types.ERROR, message: "Error filtering" };

  if (output instanceof HTMLCanvasElement) {
    const outputImage = new Image();
    outputImage.src = output.toDataURL("image/png");

    outputImage.onload = () => {
      dispatch(filterImage(outputImage));
    };
  }

  return null;
};

export const addPaletteColor = (color: ColorRGBA) => ({
  type: types.ADD_PALETTE_COLOR,
  color
});

// FIXME: Why is it finding by name here? Fishy, potential problem when value is a valid palette name
export const setFilterOption = (optionName: string, value: any) => {
  const paletteObject = paletteList.find(p => p.name === value);

  return {
    type: types.SET_FILTER_OPTION,
    optionName,
    value: paletteObject ? paletteObject.palette : value
  };
};

export const setFilterPaletteOption = (optionName: string, value: any) => ({
  type: types.SET_FILTER_PALETTE_OPTION,
  optionName,
  value
});

export const setScale = (scale: number) => ({
  type: types.SET_SCALE,
  scale
});

export const setOutputScale = (scale: number) => ({
  type: types.SET_OUTPUT_SCALE,
  scale
});

export const setRealtimeFiltering = (enabled: boolean) => ({
  type: types.SET_REAL_TIME_FILTERING,
  enabled
});

export const saveCurrentColorPalette = (
  name: string,
  colors: Array<ColorRGBA>
) => {
  window.localStorage.setItem(
    `_palette_${name.replace(" ", "")}`,
    JSON.stringify({ type: optionTypes.PALETTE, name, colors })
  );

  THEMES[name] = colors;

  return {
    type: types.SAVE_CURRENT_COLOR_PALETTE,
    name
  };
};

export const deleteCurrentColorPalette = (name: string) => {
  window.localStorage.removeItem(`_palette_${name.replace(" ", "")}`);
  delete THEMES[name];

  return {
    type: types.DELETE_CURRENT_COLOR_PALETTE,
    name
  };
};
<commit_msg>Force video to play on load<commit_after>// @flow
/* eslint-disable import/prefer-default-export */

import * as types from "constants/actionTypes";
import * as optionTypes from "constants/optionTypes";
import { paletteList } from "palettes";
import { THEMES } from "palettes/user";

import type { ColorRGBA, Filter, FilterFunc } from "types";

export const importState = (json: string) => {
  const deserialized = JSON.parse(json);
  return {
    type: types.LOAD_STATE,
    data: deserialized
  };
};

export const setInputVolume = (volume: number) => ({
  type: types.SET_INPUT_VOLUME,
  volume
});

export const setInputPlaybackRate = (rate: number) => ({
  type: types.SET_INPUT_PLAYBACK_RATE,
  rate
});

export const setInputCanvas = (canvas: HTMLCanvasElement) => ({
  type: types.SET_INPUT_CANVAS,
  canvas
});

export const setScalingAlgorithm = (algorithm: string) => ({
  type: types.SET_SCALING_ALGORITHM,
  algorithm
});

export const loadImage = (
  image: HTMLImageElement,
  time: ?number = 0,
  video: ?HTMLVideoElement,
  dispatch: ?any
) => ({
  type: types.LOAD_IMAGE,
  image,
  time,
  video,
  dispatch
});

export const loadImageAsync = (file: File) => (dispatch: Dispatch) => {
  const reader = new FileReader();
  const image = new Image();

  reader.onload = event => {
    image.onload = () => {
      dispatch(loadImage(image, null, null, dispatch));
    };
    image.src = event.target.result;
  };

  reader.readAsDataURL(file);
};

export const loadVideoAsync = (
  file: File,
  volume: number = 1,
  playbackRate: number = 1
) => (dispatch: Dispatch) => {
  const reader = new FileReader();
  const video = document.createElement("video");

  reader.onload = event => {
    const i = new Image();
    const canvas = document.createElement("canvas");
    const ctx = canvas.getContext("2d");

    const loadFrame = () => {
      URL.revokeObjectURL(i.src);

      if (!video.paused && video.src !== "") {
        i.width = video.videoWidth;
        i.height = video.videoHeight;
        ctx.drawImage(video, 0, 0);
        canvas.toBlob(blob => {
          if (blob) {
            i.src = URL.createObjectURL(blob);
            i.onload = () => {
              if (!video.paused && video.src !== "") {
                requestAnimationFrame(loadFrame);
                dispatch(loadImage(i, video.currentTime, video, dispatch));
              }
            };
          }
        });
      }
    };

    let firstPlay = true;
    video.onplaying = () => {
      if (firstPlay) {
        firstPlay = false;
        canvas.width = video.videoWidth;
        canvas.height = video.videoHeight;
        requestAnimationFrame(loadFrame);
      }
    };

    const blob = new Blob([event.target.result]);
    video.volume = volume;
    video.src = URL.createObjectURL(blob);
    video.playbackRate = playbackRate;
    video.loop = true;
    video.autoplay = true;
    video.play();
  };

  reader.readAsArrayBuffer(file);
};

export const loadMediaAsync = (
  file: File,
  volume: number = 1,
  playbackRate: number = 1
) => {
  if (file.type.startsWith("video/")) {
    return loadVideoAsync(file, volume, playbackRate);
  }

  return loadImageAsync(file);
};

export const setConvertGrayscale = (value: boolean) => ({
  type: types.SET_GRAYSCALE,
  value
});

export const selectFilter = (name: string, filter: Filter) => ({
  type: types.SELECT_FILTER,
  name,
  filter
});

export const filterImage = (image: HTMLImageElement) => ({
  type: types.FILTER_IMAGE,
  image
});

export const filterImageAsync = (
  input: HTMLCanvasElement,
  filter: FilterFunc,
  options: ?any
) => (dispatch: Dispatch) => {
  const output = filter(input, options, dispatch);
  if (!output) return { type: types.ERROR, message: "Error filtering" };

  if (output instanceof HTMLCanvasElement) {
    const outputImage = new Image();
    outputImage.src = output.toDataURL("image/png");

    outputImage.onload = () => {
      dispatch(filterImage(outputImage));
    };
  }

  return null;
};

export const addPaletteColor = (color: ColorRGBA) => ({
  type: types.ADD_PALETTE_COLOR,
  color
});

// FIXME: Why is it finding by name here? Fishy, potential problem when value is a valid palette name
export const setFilterOption = (optionName: string, value: any) => {
  const paletteObject = paletteList.find(p => p.name === value);

  return {
    type: types.SET_FILTER_OPTION,
    optionName,
    value: paletteObject ? paletteObject.palette : value
  };
};

export const setFilterPaletteOption = (optionName: string, value: any) => ({
  type: types.SET_FILTER_PALETTE_OPTION,
  optionName,
  value
});

export const setScale = (scale: number) => ({
  type: types.SET_SCALE,
  scale
});

export const setOutputScale = (scale: number) => ({
  type: types.SET_OUTPUT_SCALE,
  scale
});

export const setRealtimeFiltering = (enabled: boolean) => ({
  type: types.SET_REAL_TIME_FILTERING,
  enabled
});

export const saveCurrentColorPalette = (
  name: string,
  colors: Array<ColorRGBA>
) => {
  window.localStorage.setItem(
    `_palette_${name.replace(" ", "")}`,
    JSON.stringify({ type: optionTypes.PALETTE, name, colors })
  );

  THEMES[name] = colors;

  return {
    type: types.SAVE_CURRENT_COLOR_PALETTE,
    name
  };
};

export const deleteCurrentColorPalette = (name: string) => {
  window.localStorage.removeItem(`_palette_${name.replace(" ", "")}`);
  delete THEMES[name];

  return {
    type: types.DELETE_CURRENT_COLOR_PALETTE,
    name
  };
};
<|endoftext|>


<commit_before>const types = {
  USERNAME: 'USERNAME',
  GET_EVENTS: 'GET_EVENTS'
};

export const submitUserName = (inputVal) => {
  return {
    type: types.USERNAME,
    username: inputVal
  };
};

export const getEvents = (data) => {
    return {
      type: types.GET_EVENTS,
      data: data
    };
  };
<commit_msg>added a get push events action<commit_after>const types = {
  USERNAME: 'USERNAME',
  GET_EVENTS: 'GET_EVENTS',
  GET_PUSH_EVENT: 'GET_PUSH_EVENT',
};

export const submitUserName = (inputVal) => {
  return {
    type: types.USERNAME,
    username: inputVal
  };
};

export const getEvents = (data) => {
    return {
      type: types.GET_EVENTS,
      data: data
    };
  };

  export const getPushEvent = (data) => {
      return {
        type: types.GET_PUSH_EVENT,
        data: data
      };
    };
<|endoftext|>


<commit_before>// Copyright 2014 LinkedIn Corp. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

/**
 * This script defines a browser, which views a url and logs the all the network traffic
 * including the requests made by the urls. Any accesses to private network is blocked
 * automatically.
 */

var fs = require('fs'),
    webpage = require('webpage'),
    system = require('system');

var browser = {};

(function(browser) {

  /**
   * Merge objects. Elements in the `dst` object will be overridden
   * if the same field exists in the `src` object.
   *
   * @param {Object} dst The destination object.
   * @param {Object} src The source object.
   */
  Object.extend = function(dst, src) {
    for (var prop in src) {
      dst[prop] = src[prop];
    }
    return dst;
  };

  /**
   * Timeout to exit the browser after making no requests.
   */
  var IDLE_TIMEOUT = 5000;

  /**
   * Timeout to end the connection to a request.
   */
  var REQUEST_TIMEOUT = 3000;

  var exitTimeoutHandle = null;

  var options = {
    useCookie: true,
    url: null,
    logFile: null,
    javascriptEnabled: true,
    hostedLocally: true,
    cookieDir: null,
    debug: false,
    ipLookupUrl: null
  };

  var pageResources = null;

 /**
  * Call the callback function after the idle timeout.
  *
  * @param {Function} callback The function to be called after the idle timeout.
  */
  var resetExitTimeoutHandle = function(callback, timeout) {

    clearTimeout(exitTimeoutHandle);

    var timeoutStartDate = new Date();
    var _timeout = timeout != null ? timeout : IDLE_TIMEOUT;

    exitTimeoutHandle = setTimeout(function() {
      var remainingTime = _timeout - (new Date().getTime() - timeoutStartDate.getTime());
      if(remainingTime > 0 ) {
        resetExitTimeoutHandle(callback, remainingTime);
      } else if(callback) {
        setTimeout(callback, 0);
      } else {
        exit();
      }
    }, _timeout);
  };

  /**
   * Return true if the `ip` is an IP address in a private network.
   *
   * @param {String} ip The string that represents an IP address.
   * @return {boolean} true if the `ip` represents an IP address in a private network.
   */
  var isPrivateIp = function(ip) {
    return /^(127\.0\.0\.1|192\.168\.|172\.(1[6-9]|2[0-9]|3[0-1])\.|10\.)/.test(ip);
  };

  /**
   * Return true if the `url` is a location inside of a private network.
   *
   * @param {String} url The url.
   * @return {boolean} true if the `url` represents a location inside of a private network.
   */
  var isPrivateNetwork = function(url) {
    var ip = undefined;

    if(options.ipLookupUrl) {
      var xhr = new XMLHttpRequest();
      xhr.open('GET', options.ipLookupUrl + '?url=' + encodeURIComponent(url), false);
      xhr.onreadystatechange = function() {
        if (xhr.readyState == 4 && xhr.status == 200) {
          try {
            var json = JSON.parse(xhr.responseText);
            ip = json.ip;
          } catch(err) {}
        }
      };
      xhr.send(null);
    }
    return ip && isPrivateIp(ip);
  };

  /**
   * Initialize the page load.
   *
   * @param {Object} page An instance of PhantomJS's WebPage object.
   * @param {Function} callback The function to be called after the idle timeout.
   */
  var initPage = function(page, callback) {
    if(!page.resources) {
      page.resources = {};
    }
    page.settings.webSecurityEnabled = false;
    page.settings.javascriptEnabled = options.javascriptEnabled;
    page.settings.resourceTimeout = REQUEST_TIMEOUT;

    page.onResourceRequested = function(requestData, networkRequest) {
      resetExitTimeoutHandle(callback);
      page.resources[requestData.url] = {
        request: requestData,
        response: null,
        error: null
      };

      // Abort requests to private network if ads are not hosted locally
      // or ads are hosted locally but requests are made to inside of a private network.
      if(!options.debug && (!options.hostedLocally || Object.keys(page.resources).length > 1) && isPrivateNetwork(requestData.url)) {
        page.resources[requestData.url].error = {
          id: requestData.id,
          url: requestData.url,
          errorCode: 999,
          errorString: 'Access to private network'
        };
        networkRequest.abort();
      }
    };

    page.onResourceReceived = function(response) {
      resetExitTimeoutHandle(callback);
      if(response.stage === 'end' && page.resources[response.url]) {
        page.resources[response.url].response = response;
      }
    };

    page.onResourceError = function(resourceError) {
      resetExitTimeoutHandle(callback);
     if(page.resources[resourceError.url] && !page.resources[resourceError.url].error) {
        page.resources[resourceError.url].error = resourceError;
      }
    };
  };

  /**
   * Quit this process. The network and error logs are saved in a JSON format
   * in the log file.
   */
  var exit = function() {
    fs.write(options.logFile, JSON.stringify(pageResources), 'w');
    phantom.exit();
  };

  /**
   * Load cookies on the browser.
   */
  var setCookies = function() {
    if(!options.cookieDir || !fs.exists(options.cookieDir) || !fs.isDirectory(options.cookieDir)) {
      return;
    }

    var regiesterCookie = function(name, value, domain) {
      phantom.addCookie({
        name  : name,
        value : value,
        domain: domain
      });
    };

    fs.list(options.cookieDir).forEach(function(file) {
      if (file !== '.' && file !== '..') {
        var domain = file.substr(0, file.indexOf('.txt'));
        var content = fs.read(options.cookieDir + '/' + file);
        var cookies = content.split(';').map(function(a){
          var c = a.trim();
          var i = c.indexOf('=');
          regiesterCookie(c.substr(0, i), c.substr(i + 1), domain);
        });
      }
    });
  };

  /**
   * Start the browser.
   *
   * @param {Object} opts The object to override the `options`, which
   *   defines the default settings of this browser.
   */
  var run = function(opts) {
    options = Object.extend(options, opts);

    if(options.useCookie) {
      phantom.cookiesEnabled = true;
      setCookies();
    }

    if(options.url) {
      var page = webpage.create();
      initPage(page, exit);
      page.open(options.url);
      pageResources = page.resources;
    } else {
      exit();
    }
  };

  browser.run = run;

})(browser);

var options = {};
var argIndex = 1;

/**
 * Parse the command line arguments
 *
 * @param {boolean} --use-cookie Enable/disable the use of cookies on the browser.
 * @param {boolean} --enable-javascript Enable/disable JavaScript on the browser.
 * @param {boolean} --hosted-locally A boolean value if the ads are hosted on the local server.
 * @param {String} --log-file The location of log file.
 * @param {String} --url The URL to be scanned.
 * @param {String} --cookie-dir The directory where cookies are defined.
 * @param {String} --debug Turn on the debug mode, which allows access to private network.
 * @param {String} --iplookup-url Url for iplookup service.
 */
 while(argIndex < system.args.length && system.args[argIndex].indexOf("--") === 0){
  var option = system.args[argIndex].substring(2);
  switch(option) {
  case "use-cookie":
    argIndex++;
    options.useCookie = system.args[argIndex].trim() != 'false';
    break;
  case "enable-javascript":
    argIndex++;
    options.javascriptEnabled = system.args[argIndex].trim() != 'false';
    break;
  case "hosted-locally":
    argIndex++;
    options.hostedLocally = system.args[argIndex].trim() != 'false';
    break;
  case "log-file":
    argIndex++;
    options.logFile = system.args[argIndex].replace(/^\"|\"$/g, '').replace(/^\'|\'$/g, '').trim();
    break;
  case "url":
    argIndex++;
    options.url = system.args[argIndex].replace(/^\"|\"$/g, '').replace(/^\'|\'$/g, '').trim();
    break;
  case "cookie-dir":
    argIndex++;
    options.cookie_dir = system.args[argIndex].replace(/^\"|\"$/g, '').replace(/^\'|\'$/g, '').trim();
    break;
  case "debug":
    argIndex++;
    options.debug = system.args[argIndex].trim() == 'true';
    break;
  case "iplookup-url":
    argIndex++;
    options.ipLookupUrl = system.args[argIndex].replace(/^\"|\"$/g, '').replace(/^\'|\'$/g, '').trim();
    break;
  }
  argIndex++;
}
browser.run(options);
<commit_msg>Avoid redundant ip-lookup for data: and blob: schemas<commit_after>// Copyright 2014 LinkedIn Corp. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

/**
 * This script defines a browser, which views a url and logs the all the network traffic
 * including the requests made by the urls. Any accesses to private network is blocked
 * automatically.
 */

var fs = require('fs'),
    webpage = require('webpage'),
    system = require('system');

var browser = {};

(function(browser) {

  /**
   * Merge objects. Elements in the `dst` object will be overridden
   * if the same field exists in the `src` object.
   *
   * @param {Object} dst The destination object.
   * @param {Object} src The source object.
   */
  Object.extend = function(dst, src) {
    for (var prop in src) {
      dst[prop] = src[prop];
    }
    return dst;
  };

  /**
   * Timeout to exit the browser after making no requests.
   */
  var IDLE_TIMEOUT = 5000;

  /**
   * Timeout to end the connection to a request.
   */
  var REQUEST_TIMEOUT = 3000;

  var exitTimeoutHandle = null;

  var options = {
    useCookie: true,
    url: null,
    logFile: null,
    javascriptEnabled: true,
    hostedLocally: true,
    cookieDir: null,
    debug: false,
    ipLookupUrl: null
  };

  var pageResources = null;

 /**
  * Call the callback function after the idle timeout.
  *
  * @param {Function} callback The function to be called after the idle timeout.
  */
  var resetExitTimeoutHandle = function(callback, timeout) {

    clearTimeout(exitTimeoutHandle);

    var timeoutStartDate = new Date();
    var _timeout = timeout != null ? timeout : IDLE_TIMEOUT;

    exitTimeoutHandle = setTimeout(function() {
      var remainingTime = _timeout - (new Date().getTime() - timeoutStartDate.getTime());
      if(remainingTime > 0 ) {
        resetExitTimeoutHandle(callback, remainingTime);
      } else if(callback) {
        setTimeout(callback, 0);
      } else {
        exit();
      }
    }, _timeout);
  };

  /**
   * Return true if the `ip` is an IP address in a private network.
   *
   * @param {String} ip The string that represents an IP address.
   * @return {boolean} true if the `ip` represents an IP address in a private network.
   */
  var isPrivateIp = function(ip) {
    return /^(127\.0\.0\.1|192\.168\.|172\.(1[6-9]|2[0-9]|3[0-1])\.|10\.)/.test(ip);
  };

  /**
   * Return true if the `url` is a location inside of a private network.
   *
   * @param {String} url The url.
   * @return {boolean} true if the `url` represents a location inside of a private network.
   */
  var isPrivateNetwork = function(url) {
    var ip = undefined;

    if(url && !/^(data:|blob:)/.test(url) && options.ipLookupUrl) {
      var xhr = new XMLHttpRequest();
      xhr.open('GET', options.ipLookupUrl + '?url=' + encodeURIComponent(url), false);
      xhr.onreadystatechange = function() {
        if (xhr.readyState == 4 && xhr.status == 200) {
          try {
            var json = JSON.parse(xhr.responseText);
            ip = json.ip;
          } catch(err) {}
        }
      };
      xhr.send(null);
    }
    return ip && isPrivateIp(ip);
  };

  /**
   * Initialize the page load.
   *
   * @param {Object} page An instance of PhantomJS's WebPage object.
   * @param {Function} callback The function to be called after the idle timeout.
   */
  var initPage = function(page, callback) {
    if(!page.resources) {
      page.resources = {};
    }
    page.settings.webSecurityEnabled = false;
    page.settings.javascriptEnabled = options.javascriptEnabled;
    page.settings.resourceTimeout = REQUEST_TIMEOUT;

    page.onResourceRequested = function(requestData, networkRequest) {
      resetExitTimeoutHandle(callback);
      page.resources[requestData.url] = {
        request: requestData,
        response: null,
        error: null
      };

      // Abort requests to private network if ads are not hosted locally
      // or ads are hosted locally but requests are made to inside of a private network.
      if(!options.debug && (!options.hostedLocally || Object.keys(page.resources).length > 1) && isPrivateNetwork(requestData.url)) {
        page.resources[requestData.url].error = {
          id: requestData.id,
          url: requestData.url,
          errorCode: 999,
          errorString: 'Access to private network'
        };
        networkRequest.abort();
      }
    };

    page.onResourceReceived = function(response) {
      resetExitTimeoutHandle(callback);
      if(response.stage === 'end' && page.resources[response.url]) {
        page.resources[response.url].response = response;
      }
    };

    page.onResourceError = function(resourceError) {
      resetExitTimeoutHandle(callback);
     if(page.resources[resourceError.url] && !page.resources[resourceError.url].error) {
        page.resources[resourceError.url].error = resourceError;
      }
    };
  };

  /**
   * Quit this process. The network and error logs are saved in a JSON format
   * in the log file.
   */
  var exit = function() {
    fs.write(options.logFile, JSON.stringify(pageResources), 'w');
    phantom.exit();
  };

  /**
   * Load cookies on the browser.
   */
  var setCookies = function() {
    if(!options.cookieDir || !fs.exists(options.cookieDir) || !fs.isDirectory(options.cookieDir)) {
      return;
    }

    var regiesterCookie = function(name, value, domain) {
      phantom.addCookie({
        name  : name,
        value : value,
        domain: domain
      });
    };

    fs.list(options.cookieDir).forEach(function(file) {
      if (file !== '.' && file !== '..') {
        var domain = file.substr(0, file.indexOf('.txt'));
        var content = fs.read(options.cookieDir + '/' + file);
        var cookies = content.split(';').map(function(a){
          var c = a.trim();
          var i = c.indexOf('=');
          regiesterCookie(c.substr(0, i), c.substr(i + 1), domain);
        });
      }
    });
  };

  /**
   * Start the browser.
   *
   * @param {Object} opts The object to override the `options`, which
   *   defines the default settings of this browser.
   */
  var run = function(opts) {
    options = Object.extend(options, opts);

    if(options.useCookie) {
      phantom.cookiesEnabled = true;
      setCookies();
    }

    if(options.url) {
      var page = webpage.create();
      initPage(page, exit);
      page.open(options.url);
      pageResources = page.resources;
    } else {
      exit();
    }
  };

  browser.run = run;

})(browser);

var options = {};
var argIndex = 1;

/**
 * Parse the command line arguments
 *
 * @param {boolean} --use-cookie Enable/disable the use of cookies on the browser.
 * @param {boolean} --enable-javascript Enable/disable JavaScript on the browser.
 * @param {boolean} --hosted-locally A boolean value if the ads are hosted on the local server.
 * @param {String} --log-file The location of log file.
 * @param {String} --url The URL to be scanned.
 * @param {String} --cookie-dir The directory where cookies are defined.
 * @param {String} --debug Turn on the debug mode, which allows access to private network.
 * @param {String} --iplookup-url Url for iplookup service.
 */
 while(argIndex < system.args.length && system.args[argIndex].indexOf("--") === 0){
  var option = system.args[argIndex].substring(2);
  switch(option) {
  case "use-cookie":
    argIndex++;
    options.useCookie = system.args[argIndex].trim() != 'false';
    break;
  case "enable-javascript":
    argIndex++;
    options.javascriptEnabled = system.args[argIndex].trim() != 'false';
    break;
  case "hosted-locally":
    argIndex++;
    options.hostedLocally = system.args[argIndex].trim() != 'false';
    break;
  case "log-file":
    argIndex++;
    options.logFile = system.args[argIndex].replace(/^\"|\"$/g, '').replace(/^\'|\'$/g, '').trim();
    break;
  case "url":
    argIndex++;
    options.url = system.args[argIndex].replace(/^\"|\"$/g, '').replace(/^\'|\'$/g, '').trim();
    break;
  case "cookie-dir":
    argIndex++;
    options.cookie_dir = system.args[argIndex].replace(/^\"|\"$/g, '').replace(/^\'|\'$/g, '').trim();
    break;
  case "debug":
    argIndex++;
    options.debug = system.args[argIndex].trim() == 'true';
    break;
  case "iplookup-url":
    argIndex++;
    options.ipLookupUrl = system.args[argIndex].replace(/^\"|\"$/g, '').replace(/^\'|\'$/g, '').trim();
    break;
  }
  argIndex++;
}
browser.run(options);
<|endoftext|>


<commit_before>import $ from 'jquery'
import config from '../store/config'
import Share from '../components/Share'
import Qrcode from '../components/Qrcode'
import Result from '../components/Result'
import Tvc from '../components/Tvc'
import Animal from '../components/Animal'
import ApplyResult from '../components/ApplyResult'
import Login from '../components/Login'

/*
 * LocalStorage: {token: "", user: "", star: "", winning_state: "", trialPack: ""}
 *
 * @token:         access_token
 * @star:          神器详情
 * @winning_state: 如果为空则没有抽过奖 0 => 试用装 1 => 优惠劵
 * @trialPack:     试用装申领信息
 *
**/

function setItem(key, value){
	window.localStorage.setItem(key, value)
}

export function getItem(key){
	return window.localStorage.getItem(key)
}

function removeItem(){
	window.localStorage.removeItem(key)
}

function clearItem(){
	window.localStorage.clear()
}

export function getLocal(type){
	try {
      return JSON.parse(getItem(type))
    } catch (e) {
      return null
    }
}

// 显示弹窗
export function showPanel(dom){
	$('.popup-panel').fadeOut()
	$('.'+dom).fadeIn();
}

// 隐藏弹窗
export function hidePanel(){
	$('.popup-panel').hide()
}

// 显示消息
export function showMessage(msg){
	$('.message span').text(msg);
	$('.message').addClass('active');
	setTimeout(function(){
		$('.message').removeClass('active');
	},1000)
}

// 验证登录
export function checkAuth(){
	return window.localStorage.getItem('token') ? true : false
}

// 通用验证
export function validate(val, type){
	switch (type){
		case 'mobile':
			return (/^1[3|4|5|7|8]\d{9}$/).test(val);
			break;
		case 'email':
			return (/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/).test(val);
			break;
		default:
			return false;
	}
}

// 登录
export function login(data){
	$.ajax({
		url: config.api + 'users/auth',
		method: 'POST',
		crossDomain: true,
		dataType: config.dataType,
		data: data,
		success: function(response){
			if(response.errFlg){
				if(response.errFlg === 9){
					showMessage('请重新登录')
					new Login().render('div.login-form')
					showPanel('login-form')
					return
				}
				showMessage(response.errMsg)
			}else{
				showMessage('登录成功！');

				// 储存信息
				setItem('token', response.access_token);
				setItem('user', JSON.stringify(response.user));
				if(response.star){
					setItem('star', JSON.stringify(response.star));
				}
				if(response.trialPack){
				 	setItem('trialPack', JSON.stringify(response.trialPack));
				}

				// 隐藏弹窗
				hidePanel();

				// 重新渲染Tvc
				new Tvc().render('div.tvc');
			}
		}
	})
}

// 注销
export function logout(){
	clearItem();
}

// 注册
export function register(data){
	$.ajax({
		url: config.api + 'users/create',
		method: 'POST',
		crossDomain: true,
		dataType: config.dataType,
		data: data,
		success: function(response){
			if(response.errFlg){
				if(response.errFlg === 9){
					showMessage('请重新登录')
					new Login().render('div.login-form')
					showPanel('login-form')
					return
				}
				let message = response.errMsg
				let first_error = message[Object.keys(message)[0]]
				let first_error_message = first_error[Object.keys(first_error)[0]]

				showMessage(first_error_message)
			}else{
				showMessage('注册成功！');

				// 直接判定为已登录
				setItem('token', response.access_token);
				setItem('user', JSON.stringify(response.user));
				if(response.star){
					setItem('star', JSON.stringify(response.star));
				}
				if(response.trialPack){
				 	setItem('trialPack', JSON.stringify(response.trialPack));
				}

				// 隐藏弹窗
				hidePanel();
			}
		}
	})
}

// 获取手机验证码
export function getCaptcha(mobile){
	$.ajax({
		url: config.api + 'users/verify',
		method: 'POST',
		crossDomain: true,
		dataType: config.dataType,
		data: {phone: mobile},
		success: function(response){
			if(response.errFlg){
				if(response.errFlg === 9){
					showMessage('请重新登录')
					new Login().render('div.login-form')
					showPanel('login-form')
					return
				}
				showMessage(response.errMsg)
			}else{
				showMessage('短信验证码发送成功');

				// 启动计时器
				let _this = $('.action-get-captcha')
				let leftSeconds = 60
				let _timer = setInterval(function(){
					leftSeconds --;
					console.log(leftSeconds)
					if(leftSeconds === 0){
						console.log('true')
						_this.text('获取验证码')
						clearInterval(_timer);
						return
					}
					_this.text(leftSeconds+'s')
				},1000)
			}
		}
	})
}

// 获取用户信息
export function loadUser(){
	$.ajax({
		url: config.api + 'users/user_info',
		method: 'POST',
		crossDomain: true,
		dataType: config.dataType,
		headers: {
	        "x-token": getItem('token')
	    },
		success: function(response){
			if(response.errFlg){
				if(response.errFlg === 9){
					showMessage('请重新登录')
					new Login().render('div.login-form')
					showPanel('login-form')
					return
				}
				showMessage(response.errFlg)
				clearItem()
			}else{
				setItem("user", JSON.stringify(response.user))
				setItem("star", JSON.stringify(response.star))
				setItem("trialPack", JSON.stringify(response.trialPack))

				return response.user;
			}
		}
	})
}

// 创建神器
export function createStar(star){
	$.ajax({
		url: config.api + 'stars/create',
		method: 'POST',
		crossDomain: true,
		dataType: config.dataType,
		data: {
			"star_name": star
		},
		headers: {
	        "x-token": getItem('token')
	    },
		success: function(response){
			if(response.errFlg){
				if(response.errFlg === 9){
					showMessage('请重新登录')
					new Login().render('div.login-form')
					showPanel('login-form')
					return
				}
				showMessage(response.errMsg);
				// if invalid token???
			}else{
				showMessage('创建成功');

				// 更新储存
				setItem('star', JSON.stringify(response.star));

				// 初始化选择结果页
				new Share(response.star).render('div.share-tips')
				showPanel('share-tips')

				// 重新渲染Tvc
				new Tvc().render('div.tvc');
			}
		}
	})
}

// 获取分享二维码
export function generateQrcode(starId){
	$.ajax({
		url: config.api + 'stars/qrcode',
		method: 'POST',
		crossDomain: true,
		dataType: config.dataType,
		data: {
			"star_id": starId
		},
		headers: {
	        "x-token": getItem('token')
	    },
		success: function(response){
			if(response.errFlg){
				if(response.errFlg === 9){
					showMessage('请重新登录')
					new Login().render('div.login-form')
					showPanel('login-form')
					return
				}
				showMessage(response.errMsg);
			}else{
				new Qrcode(response.qrcode).render('div.share-tips-qr')
				showPanel('share-tips-qr')
			}
		}
	})
}

// 获取奖品类别
export function getPrize(){
	$.ajax({
		url: config.api + 'stars/prize',
		method: 'GET',
		crossDomain: true,
		dataType: config.dataType,
		headers: {
	        "x-token": getItem('token')
	    },
		success: function(response){
			if(response.errFlg){
				if(response.errFlg === 9){
					showMessage('请重新登录')
					new Login().render('div.login-form')
					showPanel('login-form')
					return
				}
				showMessage(response.errMsg)
			}else{
				// 优惠券/试用装
				new Result(response.result).render('div.star-all-collected')
				showPanel('star-all-collected')

				// 更新localStorage
				if(getItem('star')){
					let _star =  JSON.parse(getItem('star'));
					_star.winning_state = response.result
					setItem('star', JSON.stringify(_star))
				}

				// 更新甜睡神器详情
				new Animal().render('div.star-detail')
			}
		}
	})
}

// 提交收货信息
export function submitApply(data) {
	$.ajax({
		url: config.api + 'users/trial_packs',
		method: 'POST',
		crossDomain: true,
		dataType: config.dataType,
		data: data,
		headers: {
	        "x-token": getItem('token')
	    },
		success: function(response){
			if(response.errFlg){
				if(response.errFlg === 9){
					showMessage('请重新登录')
					new Login().render('div.login-form')
					showPanel('login-form')
					return
				}
				showMessage(response.errMsg)
			}else{
				// 提交成功
				showMessage("试用装申领成功")

				// 更新localStorage
				setItem('trialPack', JSON.stringify(response.trialPack));

				// 更新神器详情
				new Animal().render('div.star-detail');

				// 显示提交成功信息
				new ApplyResult().render('div.apply-result-form');
				showPanel('apply-result-form');
			}
		}
	})
}
<commit_msg>鉴权失败处理<commit_after>import $ from 'jquery'
import config from '../store/config'
import Share from '../components/Share'
import Qrcode from '../components/Qrcode'
import Result from '../components/Result'
import Tvc from '../components/Tvc'
import Animal from '../components/Animal'
import ApplyResult from '../components/ApplyResult'
import Login from '../components/Login'

/*
 * LocalStorage: {token: "", user: "", star: "", winning_state: "", trialPack: ""}
 *
 * @token:         access_token
 * @star:          神器详情
 * @winning_state: 如果为空则没有抽过奖 0 => 试用装 1 => 优惠劵
 * @trialPack:     试用装申领信息
 *
**/

function setItem(key, value){
	window.localStorage.setItem(key, value)
}

export function getItem(key){
	return window.localStorage.getItem(key)
}

function removeItem(){
	window.localStorage.removeItem(key)
}

function clearItem(){
	window.localStorage.clear()
}

export function getLocal(type){
	try {
      return JSON.parse(getItem(type))
    } catch (e) {
      return null
    }
}

// 显示弹窗
export function showPanel(dom){
	$('.popup-panel').fadeOut()
	$('.'+dom).fadeIn();
}

// 隐藏弹窗
export function hidePanel(){
	$('.popup-panel').hide()
}

// 显示消息
export function showMessage(msg){
	$('.message span').text(msg);
	$('.message').addClass('active');
	setTimeout(function(){
		$('.message').removeClass('active');
	},1000)
}

// 鉴权
export function checkAuth(){
	return window.localStorage.getItem('token') ? true : false
}

// 鉴权失败处理
function authFailed(){
	localStorage.clear()
	showMessage('请重新登录')
	new Login().render('div.login-form')
	showPanel('login-form')
}

// 通用验证
export function validate(val, type){
	switch (type){
		case 'mobile':
			return (/^1[3|4|5|7|8]\d{9}$/).test(val);
			break;
		case 'email':
			return (/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/).test(val);
			break;
		default:
			return false;
	}
}

// 登录
export function login(data){
	$.ajax({
		url: config.api + 'users/auth',
		method: 'POST',
		crossDomain: true,
		dataType: config.dataType,
		data: data,
		success: function(response){
			if(response.errFlg){
				showMessage(response.errMsg)
			}else{
				showMessage('登录成功！');

				// 储存信息
				setItem('token', response.access_token);
				setItem('user', JSON.stringify(response.user));
				if(response.star){
					setItem('star', JSON.stringify(response.star));
				}
				if(response.trialPack){
				 	setItem('trialPack', JSON.stringify(response.trialPack));
				}

				// 隐藏弹窗
				hidePanel();

				// 重新渲染Tvc
				new Tvc().render('div.tvc');
			}
		}
	})
}

// 注销
export function logout(){
	clearItem();
}

// 注册
export function register(data){
	$.ajax({
		url: config.api + 'users/create',
		method: 'POST',
		crossDomain: true,
		dataType: config.dataType,
		data: data,
		success: function(response){
			if(response.errFlg){
				if(response.errFlg === 9){
					authFailed()
					return
				}
				let message = response.errMsg
				let first_error = message[Object.keys(message)[0]]
				let first_error_message = first_error[Object.keys(first_error)[0]]

				showMessage(first_error_message)
			}else{
				showMessage('注册成功！');

				// 直接判定为已登录
				setItem('token', response.access_token);
				setItem('user', JSON.stringify(response.user));
				if(response.star){
					setItem('star', JSON.stringify(response.star));
				}
				if(response.trialPack){
				 	setItem('trialPack', JSON.stringify(response.trialPack));
				}

				// 隐藏弹窗
				hidePanel();
			}
		}
	})
}

// 获取手机验证码
export function getCaptcha(mobile){
	$.ajax({
		url: config.api + 'users/verify',
		method: 'POST',
		crossDomain: true,
		dataType: config.dataType,
		data: {phone: mobile},
		success: function(response){
			if(response.errFlg){
				if(response.errFlg === 9){
					authFailed()
					return
				}
				showMessage(response.errMsg)
			}else{
				showMessage('短信验证码发送成功');

				// 启动计时器
				let _this = $('.action-get-captcha')
				let leftSeconds = 60
				let _timer = setInterval(function(){
					leftSeconds --;
					console.log(leftSeconds)
					if(leftSeconds === 0){
						console.log('true')
						_this.text('获取验证码')
						clearInterval(_timer);
						return
					}
					_this.text(leftSeconds+'s')
				},1000)
			}
		}
	})
}

// 获取用户信息
export function loadUser(){
	$.ajax({
		url: config.api + 'users/user_info',
		method: 'POST',
		crossDomain: true,
		dataType: config.dataType,
		headers: {
	        "x-token": getItem('token')
	    },
		success: function(response){
			if(response.errFlg){
				if(response.errFlg === 9){
					authFailed()
					return
				}
				showMessage(response.errFlg)
				clearItem()
			}else{
				setItem("user", JSON.stringify(response.user))
				setItem("star", JSON.stringify(response.star))
				setItem("trialPack", JSON.stringify(response.trialPack))

				return response.user;
			}
		}
	})
}

// 创建神器
export function createStar(star){
	$.ajax({
		url: config.api + 'stars/create',
		method: 'POST',
		crossDomain: true,
		dataType: config.dataType,
		data: {
			"star_name": star
		},
		headers: {
	        "x-token": getItem('token')
	    },
		success: function(response){
			if(response.errFlg){
				if(response.errFlg === 9){
					authFailed()
					return
				}
				showMessage(response.errMsg);
				// if invalid token???
			}else{
				showMessage('创建成功');

				// 更新储存
				setItem('star', JSON.stringify(response.star));

				// 初始化选择结果页
				new Share(response.star).render('div.share-tips')
				showPanel('share-tips')

				// 重新渲染Tvc
				new Tvc().render('div.tvc');
			}
		}
	})
}

// 获取分享二维码
export function generateQrcode(starId){
	$.ajax({
		url: config.api + 'stars/qrcode',
		method: 'POST',
		crossDomain: true,
		dataType: config.dataType,
		data: {
			"star_id": starId
		},
		headers: {
	        "x-token": getItem('token')
	    },
		success: function(response){
			if(response.errFlg){
				if(response.errFlg === 9){
					authFailed()
					return
				}
				showMessage(response.errMsg);
			}else{
				new Qrcode(response.qrcode).render('div.share-tips-qr')
				showPanel('share-tips-qr')
			}
		}
	})
}

// 获取奖品类别
export function getPrize(){
	$.ajax({
		url: config.api + 'stars/prize',
		method: 'GET',
		crossDomain: true,
		dataType: config.dataType,
		headers: {
	        "x-token": getItem('token')
	    },
		success: function(response){
			if(response.errFlg){
				if(response.errFlg === 9){
					authFailed()
					return
				}
				showMessage(response.errMsg)
			}else{
				// 优惠券/试用装
				new Result(response.result).render('div.star-all-collected')
				showPanel('star-all-collected')

				// 更新localStorage
				if(getItem('star')){
					let _star =  JSON.parse(getItem('star'));
					_star.winning_state = response.result
					setItem('star', JSON.stringify(_star))
				}

				// 更新甜睡神器详情
				new Animal().render('div.star-detail')
			}
		}
	})
}

// 提交收货信息
export function submitApply(data) {
	$.ajax({
		url: config.api + 'users/trial_packs',
		method: 'POST',
		crossDomain: true,
		dataType: config.dataType,
		data: data,
		headers: {
	        "x-token": getItem('token')
	    },
		success: function(response){
			if(response.errFlg){
				if(response.errFlg === 9){
					authFailed()
					return
				}
				showMessage(response.errMsg)
			}else{
				// 提交成功
				showMessage("试用装申领成功")

				// 更新localStorage
				setItem('trialPack', JSON.stringify(response.trialPack));

				// 更新神器详情
				new Animal().render('div.star-detail');

				// 显示提交成功信息
				new ApplyResult().render('div.apply-result-form');
				showPanel('apply-result-form');
			}
		}
	})
}
<|endoftext|>


<commit_before>(function (angular, window) {
  'use strict';

  var disqusModule = angular.module('ngDisqus', [ ]);

  /**
   * $disqus provider.
   */
  disqusModule.provider('$disqus', function() {
    var TYPE_EMBED = 'embed.js'; // general disqus embed script
    var TYPE_COUNT = 'count.js'; // used for count

    // Placeholder for the disqus shortname
    var shortname;

    /**
     * @return {Element} dom element for script adding
     */
    function getScriptContainer() {
      return (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]);
    }

    /**
     * @return {String} disqus shortname
     */
    function getShortname() {
      return shortname || window.disqus_shortname;
    }

    /**
     * @param {String} shortname disqus shortname
     * @param {String} file file name to add.
     * @return {String} disqus embed src with embedded shortname
     */
    function getScriptSrc(shortname, file) {
      return '//' + shortname + '.disqus.com/' + file;
    }

    /**
     * Builds the script tag
     *
     * @param {String} src script source
     * @return {Element} script element
     */
    function buildScriptTag(src) {
      var script = document.createElement('script');

      // Configure the script tag
      script.type  = 'text/javascript';
      script.async = true;
      script.src   = src;

      return script;
    }

    /**
     * Searches the given element for defined script tag
     * if its already there then return true. Otherwise return false
     *
     * @param {Element} element element to search within
     * @param {String} scriptSrc script src
     * @return {Boolean} true if its there, false if its not
     */
    function hasScriptTagInPlace(container, scriptSrc) {
      var scripts   = container.getElementsByTagName('script'),
      script, i;

      for (i = 0; i < scripts.length; i += 1) {
        script = scripts[i];

        // Check if the name contains the given values
        // We need to check with indexOf because browsers replace // with their protocol
        if (~script.src.indexOf(scriptSrc)) {
          return true;
        }
      }

      return false;
    }

    /**
     * Writes disqus globals to window object.
     * Needed for the first load. Otherwise the disqus wouldn't know what thread comments to load.
     *
     * @param {String} id disqus identifier
     * @param {String} url disqus url
     * @param {String} shortname disqus shortname
     */
    function setGlobals(id, url, shortname) {
      window.disqus_identifier = id;
      window.disqus_url        = url;
      window.disqus_shortname  = shortname;
    }

    /**
     * Refreshes the count from DISQUSWIDGETS.
     */
    function getCount() {
      var widgets = window.DISQUSWIDGETS;
      if (widgets && angular.isFunction(widgets.getCount)) {
        widgets.getCount();
      }
    }

    /**
     * Trigger the reset comment call
     * @param  {String} $location location service
     * @param  {String} id Thread id
     */
    function resetCommit($location, id) {
      window.DISQUS.reset({
        reload: true,
        config : function() {
          this.page.identifier = id;
          this.page.url        = $location.absUrl();
        }
      });
    }

    /**
     * Adds disqus script tag to header by its type.
     * If the script tag already exists in header then wont continue.
     *
     * Adds script tags by their type.
     * Currently we are using two types:
     *  1. count.js
     *  2. embed.js
     *
     * @param {String} shortname disqus shortname
     * @param {String} type disqus scirpt tag type
     */
    function addScriptTag(shortname, type) {
      var container = getScriptContainer(),
      scriptSrc = getScriptSrc(shortname, type);

      // If it already has a script tag in place then lets not do anything
      // This might happen if the user changes the page faster than then disqus can load
      if (hasScriptTagInPlace(container, scriptSrc)) {
        return;
      }

      // Build the script tag and append it to container
      container.appendChild(buildScriptTag(scriptSrc));
    }

    /**
     * @param {String} sname shortname
     */
    this.setShortname = function(sname) {
      shortname = sname;
    };

    // Provider constructor
    this.$get = [ '$location', function($location) {

      /**
       * Resets the comment for thread.
       * If disqus was not defined then it will add disqus to script tags.
       * If disqus was initialized earlier then it will just use disqus api to reset it
       *
       * @param  {String} id required thread id
       */
      function commit(id) {
        var shortname = getShortname();

        if (!angular.isDefined(shortname)) {
          throw new Error('No disqus shortname defined');
        } else if (!angular.isDefined(id)) {
          throw new Error('No disqus thread id defined');
        } else if (angular.isDefined(window.DISQUS)) {
          resetCommit($location, id);
        } else {
          setGlobals(id, $location.absUrl(), shortname);
          addScriptTag(shortname, TYPE_EMBED);
        }
      }

      /**
       * Loads the comment script tag and initiates the comments.
       * Sets the globals according to the current page.
       *
       * If the embed disqus is not added to page then adds that.
       *
       * @param {Stirng} id thread id
       */
      function loadCount(id) {
        setGlobals(id, $location.absUrl(), shortname);
        addScriptTag(getShortname(), TYPE_EMBED);
        addScriptTag(getShortname(), TYPE_COUNT);
        getCount();
      }

      // Expose public api
      return {
        commit       : commit,
        getShortname : getShortname,
        loadCount    : loadCount
      };
    }];
  });

  /**
   * Disqus thread comment directive.
   * Used to display the comments block for a thread.
   */
  disqusModule.directive('disqus', [ '$disqus', function($disqus) {

    return {
      restrict : 'AC',
      replace  : true,
      scope    : {
        id : '=disqus',
      },
      template : '

',
      link: function link(scope) {
        scope.$watch('id', function(id) {
          if (angular.isDefined(id)) {
            $disqus.commit(id);
          }
        });
      }
    };
  }]);

  /**
   * Disqus comment count directive.
   * Just wraps `disqus-identifier` to load the disqus comments count script tag on page
   */
  disqusModule.directive('disqusIdentifier', [ '$disqus', function($disqus) {
    return {
      restrict : 'A',
      link     : function(scope, elem, attr) {
        $disqus.loadCount(attr.disqusIdentifier);
      }
    };
  }]);

})(angular, this);
<commit_msg>fixed typos<commit_after>(function (angular, window) {
  'use strict';

  var disqusModule = angular.module('ngDisqus', [ ]);

  /**
   * $disqus provider.
   */
  disqusModule.provider('$disqus', function() {
    var TYPE_EMBED = 'embed.js'; // general disqus embed script
    var TYPE_COUNT = 'count.js'; // used for count

    // Placeholder for the disqus shortname
    var shortname;

    /**
     * @return {Element} dom element for script adding
     */
    function getScriptContainer() {
      return (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]);
    }

    /**
     * @return {String} disqus shortname
     */
    function getShortname() {
      return shortname || window.disqus_shortname;
    }

    /**
     * @param {String} shortname disqus shortname
     * @param {String} file file name to add.
     * @return {String} disqus embed src with embedded shortname
     */
    function getScriptSrc(shortname, file) {
      return '//' + shortname + '.disqus.com/' + file;
    }

    /**
     * Builds the script tag
     *
     * @param {String} src script source
     * @return {Element} script element
     */
    function buildScriptTag(src) {
      var script = document.createElement('script');

      // Configure the script tag
      script.type  = 'text/javascript';
      script.async = true;
      script.src   = src;

      return script;
    }

    /**
     * Searches the given element for defined script tag
     * if its already there then return true. Otherwise return false
     *
     * @param {Element} element element to search within
     * @param {String} scriptSrc script src
     * @return {Boolean} true if its there, false if its not
     */
    function hasScriptTagInPlace(container, scriptSrc) {
      var scripts   = container.getElementsByTagName('script'),
      script, i;

      for (i = 0; i < scripts.length; i += 1) {
        script = scripts[i];

        // Check if the name contains the given values
        // We need to check with indexOf because browsers replace // with their protocol
        if (~script.src.indexOf(scriptSrc)) {
          return true;
        }
      }

      return false;
    }

    /**
     * Writes disqus globals to window object.
     * Needed for the first load. Otherwise the disqus wouldn't know what thread comments to load.
     *
     * @param {String} id disqus identifier
     * @param {String} url disqus url
     * @param {String} shortname disqus shortname
     */
    function setGlobals(id, url, shortname) {
      window.disqus_identifier = id;
      window.disqus_url        = url;
      window.disqus_shortname  = shortname;
    }

    /**
     * Refreshes the count from DISQUSWIDGETS.
     */
    function getCount() {
      var widgets = window.DISQUSWIDGETS;
      if (widgets && angular.isFunction(widgets.getCount)) {
        widgets.getCount();
      }
    }

    /**
     * Trigger the reset comment call
     * @param  {String} $location location service
     * @param  {String} id Thread id
     */
    function resetCommit($location, id) {
      window.DISQUS.reset({
        reload: true,
        config : function() {
          this.page.identifier = id;
          this.page.url        = $location.absUrl();
        }
      });
    }

    /**
     * Adds disqus script tag to header by its type.
     * If the script tag already exists in header then wont continue.
     *
     * Adds script tags by their type.
     * Currently we are using two types:
     *  1. count.js
     *  2. embed.js
     *
     * @param {String} shortname disqus shortname
     * @param {String} type disqus script tag type
     */
    function addScriptTag(shortname, type) {
      var container = getScriptContainer(),
      scriptSrc = getScriptSrc(shortname, type);

      // If it already has a script tag in place then lets not do anything
      // This might happen if the user changes the page faster than then disqus can load
      if (hasScriptTagInPlace(container, scriptSrc)) {
        return;
      }

      // Build the script tag and append it to container
      container.appendChild(buildScriptTag(scriptSrc));
    }

    /**
     * @param {String} sname shortname
     */
    this.setShortname = function(sname) {
      shortname = sname;
    };

    // Provider constructor
    this.$get = [ '$location', function($location) {

      /**
       * Resets the comment for thread.
       * If disqus was not defined then it will add disqus to script tags.
       * If disqus was initialized earlier then it will just use disqus api to reset it
       *
       * @param  {String} id required thread id
       */
      function commit(id) {
        var shortname = getShortname();

        if (!angular.isDefined(shortname)) {
          throw new Error('No disqus shortname defined');
        } else if (!angular.isDefined(id)) {
          throw new Error('No disqus thread id defined');
        } else if (angular.isDefined(window.DISQUS)) {
          resetCommit($location, id);
        } else {
          setGlobals(id, $location.absUrl(), shortname);
          addScriptTag(shortname, TYPE_EMBED);
        }
      }

      /**
       * Loads the comment script tag and initiates the comments.
       * Sets the globals according to the current page.
       *
       * If the embed disqus is not added to page then adds that.
       *
       * @param {String} id thread id
       */
      function loadCount(id) {
        setGlobals(id, $location.absUrl(), shortname);
        addScriptTag(getShortname(), TYPE_EMBED);
        addScriptTag(getShortname(), TYPE_COUNT);
        getCount();
      }

      // Expose public api
      return {
        commit       : commit,
        getShortname : getShortname,
        loadCount    : loadCount
      };
    }];
  });

  /**
   * Disqus thread comment directive.
   * Used to display the comments block for a thread.
   */
  disqusModule.directive('disqus', [ '$disqus', function($disqus) {

    return {
      restrict : 'AC',
      replace  : true,
      scope    : {
        id : '=disqus',
      },
      template : '

',
      link: function link(scope) {
        scope.$watch('id', function(id) {
          if (angular.isDefined(id)) {
            $disqus.commit(id);
          }
        });
      }
    };
  }]);

  /**
   * Disqus comment count directive.
   * Just wraps `disqus-identifier` to load the disqus comments count script tag on page
   */
  disqusModule.directive('disqusIdentifier', [ '$disqus', function($disqus) {
    return {
      restrict : 'A',
      link     : function(scope, elem, attr) {
        $disqus.loadCount(attr.disqusIdentifier);
      }
    };
  }]);

})(angular, this);
<|endoftext|>


<commit_before>import { db } from '../main';

export const createTypingTest = (req, res) => {
  const { lang, createdAt, finished } = req.body;

  db.query('INSERT INTO typing_tests(language, created_at) ' +
    'VALUES ($1, $2) RETURNING id', [lang, createdAt])
    .then(result => {
      if (result.rows.length !== 1)
        return res.status(501).end();
      else {
        const typingTestId = result.rows[0].id;
        res.set('Location', '/api/typingtests/' + typingTestId);
        res.status(201).end();
      }
    })
    .catch(err => {
      return res.status(501).json({ error: err.message });
    });
};

export const getCompetitions = (req, res) => {
  const { finished, count, from } = req.query;

  loadCompetitions(finished, count, from)
    .then(rows => {
      res.status(200).json({ competitions: rows });
    })
    .catch(err => {
      res.status(500).json({ error: err.message });
    });
};

/*
 * Loads competition records.
 * args:
 *  finished: false/true
 *  limit: max number of rows to fetch
 *  offset: row number start from (0-based)
 *
 * Returns a new promise that resolves with an array of rows returned
 * by the database, or rejects with an error.
 */
const loadCompetitions = (finished, limit, offset) => {
  let statusFilter = 'WHERE competition=true';
  let limitClause = '';
  let offsetClause = '';

  if (finished === 'true' || finished === 'false')
    statusFilter += ' AND finished=' + finished;

  if (!isNaN(parseInt(limit)))
    limitClause = ' LIMIT ' + limit;

  if (!isNaN(parseInt(offset)))
    offsetClause = ' OFFSET ' + offset;

  return new Promise((resolve, reject) => {
    db.query('SELECT id, language, created_at, finished FROM typing_tests ' +
      statusFilter + limitClause + offsetClause)
    .then(result => {
      resolve(result.rows);
    })
    .catch(err => {
      reject(err);
    });
  });
};
<commit_msg>Expect competition flag in POST /api/typingtests<commit_after>import { db } from '../main';

export const createTypingTest = (req, res) => {
  const { lang, createdAt, finished, competition } = req.body;

  db.query('INSERT INTO typing_tests(language, created_at, competition) ' +
    'VALUES ($1, $2, $3) RETURNING id', [lang, createdAt, competition])
    .then(result => {
      if (result.rows.length !== 1)
        return res.status(501).end();
      else {
        const typingTestId = result.rows[0].id;

        res.set('Location', '/api/typingtests/' + typingTestId);
        res.status(201).end();
      }
    })
    .catch(err => {
      return res.status(501).json({ error: err.message });
    });
};

export const getCompetitions = (req, res) => {
  const { finished, count, from } = req.query;

  loadCompetitions(finished, count, from)
    .then(rows => {
      res.status(200).json({ competitions: rows });
    })
    .catch(err => {
      res.status(500).json({ error: err.message });
    });
};

/*
 * Loads competition records.
 * args:
 *  finished: false/true
 *  limit: max number of rows to fetch
 *  offset: row number start from (0-based)
 *
 * Returns a new promise that resolves with an array of rows returned
 * by the database, or rejects with an error.
 */
const loadCompetitions = (finished, limit, offset) => {
  let statusFilter = 'WHERE competition=true';
  let limitClause = '';
  let offsetClause = '';

  if (finished === 'true' || finished === 'false')
    statusFilter += ' AND finished=' + finished;

  if (!isNaN(parseInt(limit)))
    limitClause = ' LIMIT ' + limit;

  if (!isNaN(parseInt(offset)))
    offsetClause = ' OFFSET ' + offset;

  return new Promise((resolve, reject) => {
    db.query('SELECT id, language, created_at, finished FROM typing_tests ' +
      statusFilter + limitClause + offsetClause)
    .then(result => {
      resolve(result.rows);
    })
    .catch(err => {
      reject(err);
    });
  });
};
<|endoftext|>


<commit_before>import Bootstrap from './bootstrap';

export { default as component } from './decorators/component';
export { default as view } from './decorators/view';
export { default as style } from './decorators/style';
export { default as on } from './decorators/on';
export { default as model } from './decorators/model';
export { default as modelpool } from './decorators/modelpool';
<commit_msg>src/app-decorators.js: expose libs/*.js<commit_after>import Bootstrap from './bootstrap';

// Decorators
export { default as component } from './decorators/component';
export { default as view } from './decorators/view';
export { default as style } from './decorators/style';
export { default as on } from './decorators/on';
export { default as model } from './decorators/model';
export { default as modelpool } from './decorators/modelpool';

// Libraries
export { default as CustomElement } from './libs/customelement';
export { default as Eventhandler } from './libs/eventhandler';
export { default as View } from './libs/view';
export { default as Router } from './apps/router';
export { default as Pubsub } from './apps/pubsub';
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may obtain
 * a copy of the License at
 *
 * 	http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

/**
 * The Storyboard root application module.
 *
 * This module contains the entire, standalone application for the Storyboard
 * ticket tracking web client.
 *
 * @author Michael Krotscheck
 */
angular.module('storyboard',
        [ 'sb.services', 'sb.templates', 'sb.pages', 'sb.projects', 'sb.auth',
            'sb.teams', 'sb.project_groups', 'ui.router']
    )
    .config(function ($provide, $stateProvider, $urlRouterProvider,
                      $locationProvider, $httpProvider) {
        'use strict';

        // Default URL hashbang route
        $urlRouterProvider.otherwise('/');

        // Override the hash prefix for Google's AJAX crawling.
        $locationProvider.hashPrefix('!');

        // Set an intial home page.
        $stateProvider
            .state('index', {
                url: '/',
                templateUrl: 'app/templates/index.html'
            });

        // Attach common request headers out of courtesy to the API
        $httpProvider.defaults.headers.common['X-Client'] = 'Storyboard';

    })
    .run(function ($log, $rootScope, $location) {
        'use strict';

        // Listen to changes on the root scope. If it's an error in the state
        // changes (i.e. a 404) take the user back to the index.
        $rootScope.$on('$stateChangeError',
            function () {
                $location.path('/');
            });
    });<commit_msg>Fix misspellings in storyboard-webclient<commit_after>/*
 * Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may obtain
 * a copy of the License at
 *
 * 	http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

/**
 * The Storyboard root application module.
 *
 * This module contains the entire, standalone application for the Storyboard
 * ticket tracking web client.
 *
 * @author Michael Krotscheck
 */
angular.module('storyboard',
        [ 'sb.services', 'sb.templates', 'sb.pages', 'sb.projects', 'sb.auth',
            'sb.teams', 'sb.project_groups', 'ui.router']
    )
    .config(function ($provide, $stateProvider, $urlRouterProvider,
                      $locationProvider, $httpProvider) {
        'use strict';

        // Default URL hashbang route
        $urlRouterProvider.otherwise('/');

        // Override the hash prefix for Google's AJAX crawling.
        $locationProvider.hashPrefix('!');

        // Set an initial home page.
        $stateProvider
            .state('index', {
                url: '/',
                templateUrl: 'app/templates/index.html'
            });

        // Attach common request headers out of courtesy to the API
        $httpProvider.defaults.headers.common['X-Client'] = 'Storyboard';

    })
    .run(function ($log, $rootScope, $location) {
        'use strict';

        // Listen to changes on the root scope. If it's an error in the state
        // changes (i.e. a 404) take the user back to the index.
        $rootScope.$on('$stateChangeError',
            function () {
                $location.path('/');
            });
    });
<|endoftext|>


<commit_before>/**
 * Created by EXTIGLGCORREAG on 13/05/2014.
 */
'use strict';
/*jslint unparam: true, indent: 4 */
var express = require('express');
// var path = require('path');
var bodyParser = require('body-parser');
var config = require('./config');

var app = express();

app.use(bodyParser());

var port = process.env.PORT || config.server.port;

var router = express.Router();

router.get('/', function (req, res) {
    res.send(200);
});

app.use('/api/v' + config.api.latestVersion, router);
// aa     aaa

app.listen(port);
console.log('Magic happens on port: ' + port);

module.exports = app;<commit_msg>removed commented code<commit_after>/**
 * Created by EXTIGLGCORREAG on 13/05/2014.
 */
'use strict';
/*jslint unparam: true, indent: 4 */
var express = require('express');
// var path = require('path');
var bodyParser = require('body-parser');
var config = require('./config');

var app = express();

app.use(bodyParser());

var port = process.env.PORT || config.server.port;

var router = express.Router();

router.get('/', function (req, res) {
    res.send(200);
});

app.use('/api/v' + config.api.latestVersion, router);

app.listen(port);
console.log('Magic happens on port: ' + port);

module.exports = app;<|endoftext|>


<commit_before>/*
 * Tangram
 * Copyright 2009 Baidu Inc. All rights reserved.
 */

///import baidu.ui.createUI;

///import baidu.dom.setAttr;
///import baidu.dom.setStyles;
///import baidu.dom._styleFilter.px;
///import baidu.dom._styleFixer.opacity;

///import baidu.string.format;

///import baidu.browser.ie;
///import baidu.event.on;
///import baidu.event.un;
///import baidu.page.getScrollLeft;
///import baidu.page.getScrollTop;
///import baidu.lang.isNumber;
///import baidu.object.each;
///import baidu.object.extend;
///import baidu.array.each;
///import baidu.dom.getAttr;

///import baidu.dom.getAncestorBy;
///import baidu.dom.getStyle;
///import baidu.dom.getPosition;
///import baidu.dom.children;

///import baidu.lang.instance;

///import baidu.page.getViewWidth;
///import baidu.page.getViewHeight;

//添加对flash的隐藏和显示
//在webkit中，使用iframe加div的方式遮罩wmode为window的flash会时性能下降到无法忍受的地步
//在Gecko中，使用透明的iframe无法遮住wmode为window的flash
//在其余浏览器引擎中wmode为window的flash会被遮罩，处于不可见状态
//因此，直接将wmode为window的flash隐藏，保证页面最小限度的修改

baidu.ui.Modal = baidu.ui.createUI(function(options) {
    var me = this,
        container = (options && options.container) ? baidu.g(options.container) : null;

    !container && (container = document.body);
    if (!container.id) {
        container.id = me.getId('container');
    }

    me.containerId = container.id;
    me.styles = {
        color: '#000000',
        opacity: 0.6,
        zIndex: 1000
    };

}).extend(
    /**
     *  @lends baidu.ui.Dialog.prototype
     */
{
    uiType: 'modal',
    _showing: false,

    /**
     * 获取modal的Container
     * @public
     * @return {HTMLElement} container.
     */
    getContainer: function() {
        var me = this;
        return baidu.g(me.containerId);
    },

    /**
     * 渲染遮罩层
     * @public
     * @return {NULL}
     * */
    render: function() {
        var me = this,
            modalInstance,
            style,
            main,
            id = me.containerId,
            container = baidu.g(me.containerId);

        //当该container中已经存在modal时
        //将所需参数付给当前的modalInstance
        if (modalInstance = baidu.ui.Modal.collection[id]) {
            me.mainId = modalInstance.mainId;
            main = me.getMain();
        }else {
            //如果不存在modal,则创建新的modal
            main = me.renderMain();
            if (container !== document.body) {
                container.appendChild(main);
            }
            //将参数写入
            baidu.ui.Modal.collection[id] = {
                mainId: me.mainId,
                instance: [],
                flash:{}
            };
        }

        me.dispatchEvent('onload');
    },

    /**
     * 显示遮罩层
     * @public
     * @param  {Object} options     显示选项,任何合法的style属性.
     * @return {NULL}
     */
    show: function(options) {
        var me = this,
            container = me.getContainer(),
            main = me.getMain(),
            containerId = me.containerId,
            modalInstanceOptions = baidu.ui.Modal.collection[containerId],
            length = modalInstanceOptions.instance.length,
            lastTop;

        if (me._showing)
            return;

        if (length > 0) {
            lastTop = baidu.lang.instance(modalInstanceOptions.instance[length - 1]);
            lastTop && lastTop._removeHandler();
        }
        options = options || {};
        me._show(options.styles || {});
        main.style.display = 'block';

        //将在此层中隐藏flash入库
        modalInstanceOptions.flash[me.guid] = me._hideFlash();

        //将自己的guid加在guid最后
        modalInstanceOptions.instance.push(me.guid);
        me._showing = true;

        me.dispatchEvent('onshow');
    },

    /**
     * 更新遮罩层，绑定window.resize & window.scroll
     * @private
     * @param {Object} styles
     * @return {NULL}
     */
    _show: function(styles) {
        var me = this;

        me._getModalStyles(styles || {});
        me._update();

        me.windowHandler = me.getWindowHandle();
        baidu.on(window, 'resize', me.windowHandler);
        baidu.on(window, 'scroll', me.windowHandler);
    },

    /**
     * 隐藏遮罩层
     * @public
     * @return {NULL}
     */
    hide: function() {
        var me = this;
        me._hide();
        me.dispatchEvent('onhide');
    },

    _hide: function(){
        var me = this,
            containerId = me.containerId,
            modalInstanceOptions = baidu.ui.Modal.collection[containerId],
            flash = modalInstanceOptions.flash[me.guid],
            main = me.getMain(),
            length = modalInstanceOptions.instance.length,
            lastTop;

         if (!me._showing)
             return;

         for (var i = 0; i < length; i++) {
             if (modalInstanceOptions.instance[i] == me.guid) {
                 modalInstanceOptions.instance.splice(i, 1);
                 break;
             }
         }
         length = modalInstanceOptions.instance.length;
         if (i == length) {
             me._removeHandler();
             if (length > 0) {
                 lastTop = baidu.lang.instance(modalInstanceOptions.instance[length - 1]);
                 lastTop && lastTop._show();
             }else {
                 main.style.display = 'none';
             }

             me._restoreFlash(flash);
         }else{
             //如果不是最后一个，就将该层对应的flash移动到下一层的数组中
             lastTop = baidu.lang.instance(modalInstanceOptions.instance[length - 1]);
             modalInstanceOptions.flash[lastTop.guid] = modalInstanceOptions.flash[lastTop.guid].concat(flash);
         }

         modalInstanceOptions.flash[me.guid] = [];
         me._showing = false;
    },

    /**
     * 接触window.resize和window.scroll上的事件绑定
     * @private
     * @return {NULL}
     */
    _removeHandler: function() {
        var me = this;

        baidu.un(window, 'resize', me.windowHandler);
        baidu.un(window, 'scroll', me.windowHandler);
    },

    /**
     * window.resize & window.scroll 事件调用的function
     * @public
     * @return {NULL}
     */
    getWindowHandle: function() {
        var me = this;

        return function() {
            var main = me;
            me._getModalStyles({});
            me._update();
         };
    },

    /**
     * 更新遮罩层
     * @public
     * @param  {Object} options 显示选项，同show.
     * @return {NULL}
     */
    update: function(options) {
        options = options || {};
        var me = this,
            main = me.getMain(),
            modalInstanceOptions = baidu.ui.Modal.collection[me.containerId];

        options = options || {};
        baidu.extend(me, options);

        me._getModalStyles(options.styles || {});
        me._update();
        delete(options.styles);
        baidu.extend(me, options);

        me.dispatchEvent('onupdate');
    },

    /**
     * 更新样式
     * @private
     * @return {NULL}
     */
    _update: function() {
        var me = this, main = me.getMain();
        baidu.dom.setStyles(main, me.styles);

        //TODO:iframe 补丁
        window.top !== window.self && setTimeout(function(){
            me._getModalStyles({});
            me._update();
        },16);
    },

    /**
     * 获取遮罩层相对container左上角的top和left
     * @private
     * @options {object} show传入的styles
     * @return {NULL}
     */
    _getModalStyles: function(styles) {
        var me = this,
            main = me.getMain(),
            container = me.getContainer(),
            offsetParentPosition,
            parentPosition, offsetParent;

        function getStyleNum(d,style) {
            var result = parseInt(baidu.getStyle(d, style));
            result = isNaN(result) ? 0 : result;
            result = baidu.lang.isNumber(result) ? result : 0;
            return result;
        }

        if (container !== document.body) {
            styles['width'] = container.offsetWidth;
            styles['height'] = container.offsetHeight;

            if (baidu.getStyle(container, 'position') == 'static') {
                offsetParent = main.offsetParent || document.body;
                offsetParentPosition = baidu.dom.getPosition(offsetParent);
                parentPosition = baidu.dom.getPosition(container);
                styles['top'] = parentPosition.top - offsetParentPosition.top + getStyleNum(offsetParent, 'marginTop');
                styles['left'] = parentPosition.left - offsetParentPosition.left + getStyleNum(offsetParent, 'marginLeft');
            }
        }else {

            //如果不是ie6,并且不是quirk模式，设置为fixed
            if ((baidu.browser.ie >= 7 || !baidu.browser.ie ) && document.compatMode != 'BackCompat') {
                styles['position'] = 'fixed';
                styles['top'] = 0;
                styles['left'] = 0;

                styles['width'] = '100%';
                styles['height'] = '100%';
            }else {
                styles['top'] = baidu.page.getScrollTop();
                styles['left'] = baidu.page.getScrollLeft();

                styles['width'] = baidu.page.getViewWidth();
                styles['height'] = baidu.page.getViewHeight();
            }
        }

        //更新styles
        baidu.extend(me.styles, styles);
        me.styles['backgroundColor'] = me.styles['color'] || me.styles['backgroundColor'];
        delete(me.styles['color']);
    },

    /**
     * 隐藏flash
     * @private
     * @return {Null}
     */
    _hideFlash: function(){
        var me = this,
            container = me.getContainer(),
            elements = container.getElementsByTagName('object'),
            result = [];

        //只隐藏wmode = window的flash
        baidu.each(elements, function(item){
            var isWinMode = true;

            if(baidu.dom.getAncestorBy(item,function(element){
                if(baidu.getStyle(element, 'zIndex') > me.styles.zIndex){
                    return true;
                }

                return false;
            })){
                return;
            }

            baidu.each(baidu.dom.children(item), function(param){
                if(baidu.getAttr(param, 'name') == 'wmode' && baidu.getAttr(param, 'value') != 'window'){
                    isWinMode = false;
                }
            });

            if(isWinMode){
                result.push([item,baidu.getStyle(item, 'visibility')]);
                item.style.visibility = 'hidden';
            }
        });

        return result;
    },

    /**
     * 还原flash
     * @private
     * @return {Null}
     */
    _restoreFlash: function(flash){
        baidu.each(flash, function(item){
            if(item[0] != null){
                item[0].style.visibility = item[1];
            }
        });
    },

    /**
     * 销毁
     * @public
     * @return {Null}
     */
    dispose: function(){
        var me = this;

        me._hide();
        me.dispatchEvent('ondispose');
        baidu.lang.Class.prototype.dispose.call(me);
    }
});

//存储所有的modal参数
baidu.ui.Modal.collection = {};
<commit_msg>bug fix<commit_after>/*
 * Tangram
 * Copyright 2009 Baidu Inc. All rights reserved.
 */

///import baidu.ui.createUI;

///import baidu.dom.setAttr;
///import baidu.dom.setStyles;
///import baidu.dom._styleFilter.px;
///import baidu.dom._styleFixer.opacity;

///import baidu.string.format;

///import baidu.browser.ie;
///import baidu.event.on;
///import baidu.event.un;
///import baidu.page.getScrollLeft;
///import baidu.page.getScrollTop;
///import baidu.lang.isNumber;
///import baidu.object.each;
///import baidu.object.extend;
///import baidu.array.each;
///import baidu.dom.getAttr;

///import baidu.dom.getAncestorBy;
///import baidu.dom.getStyle;
///import baidu.dom.getPosition;
///import baidu.dom.children;

///import baidu.lang.instance;

///import baidu.page.getViewWidth;
///import baidu.page.getViewHeight;

//添加对flash的隐藏和显示
//在webkit中，使用iframe加div的方式遮罩wmode为window的flash会时性能下降到无法忍受的地步
//在Gecko中，使用透明的iframe无法遮住wmode为window的flash
//在其余浏览器引擎中wmode为window的flash会被遮罩，处于不可见状态
//因此，直接将wmode为window的flash隐藏，保证页面最小限度的修改

baidu.ui.Modal = baidu.ui.createUI(function(options) {
    var me = this,
        container = (options && options.container) ? baidu.g(options.container) : null;

    !container && (container = document.body);
    if (!container.id) {
        container.id = me.getId('container');
    }

    me.containerId = container.id;
    me.styles = {
        color: '#000000',
        opacity: 0.6,
        zIndex: 1000
    };

}).extend(
    /**
     *  @lends baidu.ui.Dialog.prototype
     */
{
    uiType: 'modal',
    _showing: false,

    /**
     * 获取modal的Container
     * @public
     * @return {HTMLElement} container.
     */
    getContainer: function() {
        var me = this;
        return baidu.g(me.containerId);
    },

    /**
     * 渲染遮罩层
     * @public
     * @return {NULL}
     * */
    render: function() {
        var me = this,
            modalInstance,
            style,
            main,
            id = me.containerId,
            container = baidu.g(me.containerId);

        //当该container中已经存在modal时
        //将所需参数付给当前的modalInstance
        if (modalInstance = baidu.ui.Modal.collection[id]) {
            me.mainId = modalInstance.mainId;
            main = me.getMain();
        }else {
            //如果不存在modal,则创建新的modal
            main = me.renderMain();
            if (container !== document.body) {
                container.appendChild(main);
            }
            //将参数写入
            baidu.ui.Modal.collection[id] = {
                mainId: me.mainId,
                instance: [],
                flash:{}
            };
        }

        me.dispatchEvent('onload');
    },

    /**
     * 显示遮罩层
     * @public
     * @param  {Object} options     显示选项,任何合法的style属性.
     * @return {NULL}
     */
    show: function(options) {
        var me = this,
            container = me.getContainer(),
            main = me.getMain(),
            containerId = me.containerId,
            modalInstanceOptions = baidu.ui.Modal.collection[containerId],
            length = modalInstanceOptions.instance.length,
            lastTop;

        if (me._showing)
            return;

        if (length > 0) {
            lastTop = baidu.lang.instance(modalInstanceOptions.instance[length - 1]);
            lastTop && lastTop._removeHandler();
        }
        options = options || {};
        me._show(options.styles || {});
        main.style.display = 'block';

        //将在此层中隐藏flash入库
        modalInstanceOptions.flash[me.guid] = me._hideFlash();

        //将自己的guid加在guid最后
        modalInstanceOptions.instance.push(me.guid);
        me._showing = true;

        me.dispatchEvent('onshow');
    },

    /**
     * 更新遮罩层，绑定window.resize & window.scroll
     * @private
     * @param {Object} styles
     * @return {NULL}
     */
    _show: function(styles) {
        var me = this;

        me._getModalStyles(styles || {});
        me._update();

        me.windowHandler = me.getWindowHandle();
        baidu.on(window, 'resize', me.windowHandler);
        baidu.on(window, 'scroll', me.windowHandler);
    },

    /**
     * 隐藏遮罩层
     * @public
     * @return {NULL}
     */
    hide: function() {
        var me = this;
        me._hide();
        me.dispatchEvent('onhide');
    },

    _hide: function(){
        var me = this,
            containerId = me.containerId,
            modalInstanceOptions = baidu.ui.Modal.collection[containerId],
            flash = modalInstanceOptions.flash[me.guid],
            main = me.getMain(),
            length = modalInstanceOptions.instance.length,
            lastTop;

         if (!me._showing)
             return;

         for (var i = 0; i < length; i++) {
             if (modalInstanceOptions.instance[i] == me.guid) {
                 modalInstanceOptions.instance.splice(i, 1);
                 break;
             }
         }
         length = modalInstanceOptions.instance.length;
         if (i == length) {
             me._removeHandler();
             if (length > 0) {
                 lastTop = baidu.lang.instance(modalInstanceOptions.instance[length - 1]);
                 lastTop && lastTop._show();
             }else {
                 main.style.display = 'none';
             }

             me._restoreFlash(flash);
         }else{
             //如果不是最后一个，就将该层对应的flash移动到下一层的数组中
             lastTop = baidu.lang.instance(modalInstanceOptions.instance[length - 1]);
             modalInstanceOptions.flash[lastTop.guid] = modalInstanceOptions.flash[lastTop.guid].concat(flash);
         }

         modalInstanceOptions.flash[me.guid] = [];
         me._showing = false;
    },

    /**
     * 接触window.resize和window.scroll上的事件绑定
     * @private
     * @return {NULL}
     */
    _removeHandler: function() {
        var me = this;

        baidu.un(window, 'resize', me.windowHandler);
        baidu.un(window, 'scroll', me.windowHandler);
    },

    /**
     * window.resize & window.scroll 事件调用的function
     * @public
     * @return {NULL}
     */
    getWindowHandle: function() {
        var me = this;

        return function() {
            me._getModalStyles({});
            me._update();
         };
    },

    /**
     * 更新遮罩层
     * @public
     * @param  {Object} options 显示选项，同show.
     * @return {NULL}
     */
    update: function(options) {
        options = options || {};
        var me = this,
            main = me.getMain(),
            modalInstanceOptions = baidu.ui.Modal.collection[me.containerId];

        options = options || {};
        baidu.extend(me, options);

        me._getModalStyles(options.styles || {});
        me._update();
        delete(options.styles);
        baidu.extend(me, options);

        me.dispatchEvent('onupdate');
    },

    /**
     * 更新样式
     * @private
     * @return {NULL}
     */
    _update: function() {
        var me = this, main = me.getMain();
        baidu.dom.setStyles(main, me.styles);

        //TODO:iframe 补丁
        window.top !== window.self && setTimeout(function(){
            me._getModalStyles({});
            me._update();
        },16);
    },

    /**
     * 获取遮罩层相对container左上角的top和left
     * @private
     * @options {object} show传入的styles
     * @return {NULL}
     */
    _getModalStyles: function(styles) {
        var me = this,
            main = me.getMain(),
            container = me.getContainer(),
            offsetParentPosition,
            parentPosition, offsetParent;

        function getStyleNum(d,style) {
            var result = parseInt(baidu.getStyle(d, style));
            result = isNaN(result) ? 0 : result;
            result = baidu.lang.isNumber(result) ? result : 0;
            return result;
        }

        if (container !== document.body) {
            styles['width'] = container.offsetWidth;
            styles['height'] = container.offsetHeight;

            if (baidu.getStyle(container, 'position') == 'static') {
                offsetParent = main.offsetParent || document.body;
                offsetParentPosition = baidu.dom.getPosition(offsetParent);
                parentPosition = baidu.dom.getPosition(container);
                styles['top'] = parentPosition.top - offsetParentPosition.top + getStyleNum(offsetParent, 'marginTop');
                styles['left'] = parentPosition.left - offsetParentPosition.left + getStyleNum(offsetParent, 'marginLeft');
            }
        }else {

            //如果不是ie6,并且不是quirk模式，设置为fixed
            if ((baidu.browser.ie >= 7 || !baidu.browser.ie ) && document.compatMode != 'BackCompat') {
                styles['position'] = 'fixed';
                styles['top'] = 0;
                styles['left'] = 0;

                styles['width'] = '100%';
                styles['height'] = '100%';
            }else {
                styles['top'] = baidu.page.getScrollTop();
                styles['left'] = baidu.page.getScrollLeft();

                styles['width'] = baidu.page.getViewWidth();
                styles['height'] = baidu.page.getViewHeight();
            }
        }

        //更新styles
        baidu.extend(me.styles, styles);
        me.styles['backgroundColor'] = me.styles['color'] || me.styles['backgroundColor'];
        delete(me.styles['color']);
    },

    /**
     * 隐藏flash
     * @private
     * @return {Null}
     */
    _hideFlash: function(){
        var me = this,
            container = me.getContainer(),
            elements = container.getElementsByTagName('object'),
            result = [];

        //只隐藏wmode = window的flash
        baidu.each(elements, function(item){
            var isWinMode = true;

            if(baidu.dom.getAncestorBy(item,function(element){
                if(baidu.getStyle(element, 'zIndex') > me.styles.zIndex){
                    return true;
                }

                return false;
            })){
                return;
            }

            baidu.each(baidu.dom.children(item), function(param){
                if(baidu.getAttr(param, 'name') == 'wmode' && baidu.getAttr(param, 'value') != 'window'){
                    isWinMode = false;
                }
            });

            if(isWinMode){
                result.push([item,baidu.getStyle(item, 'visibility')]);
                item.style.visibility = 'hidden';
            }
        });

        return result;
    },

    /**
     * 还原flash
     * @private
     * @return {Null}
     */
    _restoreFlash: function(flash){
        baidu.each(flash, function(item){
            if(item[0] != null){
                item[0].style.visibility = item[1];
            }
        });
    },

    /**
     * 销毁
     * @public
     * @return {Null}
     */
    dispose: function(){
        var me = this;

        me._hide();
        me.dispatchEvent('ondispose');
        baidu.lang.Class.prototype.dispose.call(me);
    }
});

//存储所有的modal参数
baidu.ui.Modal.collection = {};
<|endoftext|>