<commit_before>'use strict';

/*
 * Middleware to determine if a subject (user or account or service) is permitted
 * to perform an activity (permission).
 */

let authz = require('express-authorization'),
    link = require('../model/link'),
    security = require('../secure-data'),
    Promise = require('bluebird'),
    myself = require('./myself');

/*
 * A promise to determine if the user associated with the request is permitted to perform
 * the activity (permission).  First the user's permissions are checked, then each of the
 * user's roles are checked.
 */
function isPermittedAsync (req, permission)
{
    let user = req.user;
    user.permissionsChecked = true;

    //console.log('checking that', user.email, 'is permitted', permission);
    if (authz.considerSubject(user).isPermitted(permission))
        return Promise.resolve(true);

    if (user.roles && user.roles.length > 0) {
        console.log('checking that', user.email, 'has a role that permits', permission);
        return Promise
            .map(user.roles, url => myself(req).get(url).then(res => res.body))
            .filter(role => authz.considerSubject(role).isPermitted(permission))
            .any(() => true)
            .catch(e => { console.log('authz role fail', e); return false;})
//            .catch(() => false);
    }

    return Promise.resolve(false);
}

function isPermittedToViewAsync (req, resourceLink) {
    // If not a resource link, then it can be viewed.
    let r = link.tryParse(resourceLink);
    if (!r)
        return Promise.resolve(true);

    let permission = `api:${r.type}:view:${r.id}`;
    return isPermittedAsync(req, permission);
}

/*
 * Fails the request because the user is not permitted to perform the
 * activity.
 */
function denied(req, res, permission) {
    return res.sendError(
        req.user.isAuthenticated ? 403 : 401,
        `You need the permission '${permission}' to perform this activity`
    );
}

/*
 * Determines the CRUD permission from the the request.
 */
let method2Verb = {
    GET: 'view',
    POST: 'create',
    PUT: 'change',
    PATCH: 'change',
    DELETE: 'delete'
};
function resourceAccess(req) {
    let verb = method2Verb[req.method];
    if (!verb)
        throw new Error(`Cannot determine resource access permission for '${req.path}'`);

    let noun = '';
    let id = '';
    let parts = req.path.substring(1).split('/');
    if (parts.length == 1) {
        noun = parts[0];
        if (verb == 'view')
            verb = 'find';
    } else if (parts.length > 1) {
        noun = parts[0];
        id = parts[1];
    } else {
        throw new Error(`Cannot determine resource access permission for '${req.path}'`);
    }

    return `api:${noun}:${verb}` + (id ? ':' + id : '');
}

/*
 * Adds isPermittedAsync(permission) to 'req.user' and
 *      isPermittedToViewAsync(link)
 */
function authorisation (req, res, next) {
    req.user.isPermittedAsync = permission => isPermittedAsync(req, permission);
    req.user.isPermittedToViewAsync = resourceLink => isPermittedToViewAsync(req, resourceLink);
    req.user.demandAsync = (activity, resourceLink, jsonPointer) => {
        let permission;
        if (!resourceLink && !jsonPointer) {
            permission = activity;
        } else {
            let r = link.tryParse(resourceLink);
            if (!r)
                return Promise.resolve(true);

            let scope = 'api';
            let xtras = '';
            if (jsonPointer)
            {
                scope = security.securityLevelOf(jsonPointer);
                xtras = jsonPointer.replace(/\//, ':');
            }
            permission = `${scope}:${r.type}:${activity}:${r.id}${xtras}`;
        }
        return isPermittedAsync(req, permission)
            .then(permitted => {
                if (!permitted)
                    return denied(req, res, permission);
            });
    };

    req.user.permissionsChecked = false;

    next && next();
}

/*
 * Demands that the user has the permission to access this route.  If no permission, then an
 * HTTP erorr is sent as the response and the 'next' function is not called.
 *
 *     let authz = require('./authorisation')
 *
 *     // all routes demand the permission
 *     app.use(authz.demand('forex:use'));
 *
 *     // the specified route demands the permission
 *     app.get('/api/whoami', authz.demand('public:view'), function(req, res) {
 */
authorisation.demand = (permission) => {
    return (req, res, next) => {
        return isPermittedAsync(req, permission)
            .then(permitted => {
                if (!permitted)
                    return denied(req, res, permission);
                next && next();
            });
    };
};

/*
 * Based on the request determine the permissionactivity that is needed for
 * the activity, such as 'POST /api/bear' needs 'api:bear:create'.  Then check
 * that the user is permitted the activity.  If not then denied is called.
 *
 * This intended to be placed in an app that performs CRUD operations; such as
 *
 *    app.use(require('./authorisation').demandResourceAccess());
 *
 * Then every route (app.get, app.post, ...) will check the user's permissions
 * to access the resource.
 */
authorisation.demandResourceAccess = () => {
    return (req, res, next) => {
        let permission = resourceAccess(req);
        return isPermittedAsync(req, permission)
            .then(permitted => {
                if (!permitted)
                    return denied(req, res, permission);
                next && next();
            });
    };
};

authorisation.isPermittedAsync = isPermittedAsync;
authorisation.isPermittedToViewAsync = isPermittedToViewAsync;
authorisation.resourceAccess = resourceAccess;

module.exports = authorisation;
<commit_msg>better error reporting, #141<commit_after>'use strict';

/*
 * Middleware to determine if a subject (user or account or service) is permitted
 * to perform an activity (permission).
 */

let authz = require('express-authorization'),
    link = require('../model/link'),
    security = require('../secure-data'),
    Promise = require('bluebird'),
    myself = require('./myself');

/*
 * A promise to determine if the user associated with the request is permitted to perform
 * the activity (permission).  First the user's permissions are checked, then each of the
 * user's roles are checked.
 */
function isPermittedAsync (req, permission)
{
    let user = req.user;
    user.permissionsChecked = true;

    //console.log('checking that', user.email, 'is permitted', permission);
    if (authz.considerSubject(user).isPermitted(permission))
        return Promise.resolve(true);

    if (user.roles && user.roles.length > 0) {
        return Promise
            .map(user.roles, url => myself(req).get(url).then(res => res.body))
            .filter(role => authz.considerSubject(role).isPermitted(permission))
            .any(() => true)
            .catch(RangeError, () => false);
    }

    return Promise.resolve(false);
}

function isPermittedToViewAsync (req, resourceLink) {
    // If not a resource link, then it can be viewed.
    let r = link.tryParse(resourceLink);
    if (!r)
        return Promise.resolve(true);

    let permission = `api:${r.type}:view:${r.id}`;
    return isPermittedAsync(req, permission);
}

/*
 * Fails the request because the user is not permitted to perform the
 * activity.
 */
function denied(req, res, permission, details) {
    return res.sendError(
        req.user.isAuthenticated ? 403 : 401,
        `You need the permission '${permission}' to perform this activity`,
        details
    );
}

/*
 * Determines the CRUD permission from the the request.
 */
let method2Verb = {
    GET: 'view',
    POST: 'create',
    PUT: 'change',
    PATCH: 'change',
    DELETE: 'delete'
};
function resourceAccess(req) {
    let verb = method2Verb[req.method];
    if (!verb)
        throw new Error(`Cannot determine resource access permission for '${req.path}'`);

    let noun = '';
    let id = '';
    let parts = req.path.substring(1).split('/');
    if (parts.length == 1) {
        noun = parts[0];
        if (verb == 'view')
            verb = 'find';
    } else if (parts.length > 1) {
        noun = parts[0];
        id = parts[1];
    } else {
        throw new Error(`Cannot determine resource access permission for '${req.path}'`);
    }

    return `api:${noun}:${verb}` + (id ? ':' + id : '');
}

/*
 * Adds isPermittedAsync(permission) to 'req.user' and
 *      isPermittedToViewAsync(link)
 */
function authorisation (req, res, next) {
    req.user.isPermittedAsync = permission => isPermittedAsync(req, permission);
    req.user.isPermittedToViewAsync = resourceLink => isPermittedToViewAsync(req, resourceLink);
    req.user.demandAsync = (activity, resourceLink, jsonPointer) => {
        let permission;
        if (!resourceLink && !jsonPointer) {
            permission = activity;
        } else {
            let r = link.tryParse(resourceLink);
            if (!r)
                return Promise.resolve(true);

            let scope = 'api';
            let xtras = '';
            if (jsonPointer)
            {
                scope = security.securityLevelOf(jsonPointer);
                xtras = jsonPointer.replace(/\//, ':');
            }
            permission = `${scope}:${r.type}:${activity}:${r.id}${xtras}`;
        }
        return isPermittedAsync(req, permission)
            .then(permitted => {
                if (!permitted)
                    return denied(req, res, permission);
            })
            .catch(e => denied(req, res, permission, e));
    };

    req.user.permissionsChecked = false;

    next && next();
}

/*
 * Demands that the user has the permission to access this route.  If no permission, then an
 * HTTP erorr is sent as the response and the 'next' function is not called.
 *
 *     let authz = require('./authorisation')
 *
 *     // all routes demand the permission
 *     app.use(authz.demand('forex:use'));
 *
 *     // the specified route demands the permission
 *     app.get('/api/whoami', authz.demand('public:view'), function(req, res) {
 */
authorisation.demand = (permission) => {
    return (req, res, next) => {
        return isPermittedAsync(req, permission)
            .then(permitted => {
                if (!permitted)
                    return denied(req, res, permission);
                next && next();
            })
            .catch(e => denied(req, res, permission, e));
    };
};

/*
 * Based on the request determine the permissionactivity that is needed for
 * the activity, such as 'POST /api/bear' needs 'api:bear:create'.  Then check
 * that the user is permitted the activity.  If not then denied is called.
 *
 * This intended to be placed in an app that performs CRUD operations; such as
 *
 *    app.use(require('./authorisation').demandResourceAccess());
 *
 * Then every route (app.get, app.post, ...) will check the user's permissions
 * to access the resource.
 */
authorisation.demandResourceAccess = () => {
    return (req, res, next) => {
        let permission = resourceAccess(req);
        return isPermittedAsync(req, permission)
            .then(permitted => {
                if (!permitted)
                    return denied(req, res, permission);
                next && next();
            })
            .catch(e => denied(req, res, permission, e));
    };
};

authorisation.isPermittedAsync = isPermittedAsync;
authorisation.isPermittedToViewAsync = isPermittedToViewAsync;
authorisation.resourceAccess = resourceAccess;

module.exports = authorisation;
<|endoftext|>


<commit_before>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You 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.
 */

var clutch = require('extern/clutch');

function test(req, res) {
  /* TODO: show details about a module */
}

exports.urls = clutch.route([
  ['GET /$', test],
]);

<commit_msg>jslint commas<commit_after>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You 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.
 */

var clutch = require('extern/clutch');

function test(req, res) {
  /* TODO: show details about a module */
}

exports.urls = clutch.route([
  ['GET /$', test]
]);

<|endoftext|>


<commit_before>import * as App from '../constants/app';
import { base } from '../config/firebaseApp.js';

const push = (stateName, data) => base.push(stateName, { data });
const post = (stateName, data) => base.post(stateName, { data });
const remove = (endPoint) => base.remove(endPoint);

// sync系
export const postPlayingVideo = (video) => {
  if (video) {
    post('playingVideo', video);
    post('startTime', 0);
  } else {
    post('playingVideo', {});
    post('startTime', 0);
  }
  return { type: App.POST_PLAYING_VIDEO };
};
export const pushVideo = (video) => {
  push('que', video);
  return { type: App.PUSH_VIDEO };
};
export const addComment = (comment) => {
  push('comments', comment);
  return { type: App.ADD_COMMENT };
};
export const removeVideo = (video) => {
  remove(`que/${video.key}`);
  return { type: App.REMOVE_VIDEO };
};
export const changePlayed = (played) => {
  post('startTime', played);
  return { type: App.CHANGE_PLAYED, played };
};
export const play = () => ({ type: App.PLAY });
export const pause = (startTime) => {
  post('startTime', startTime);
  return { type: App.PAUSE };
};
export const playPause = (isPlaying) => {
  const playing = !isPlaying;
  post('playing', playing);
  return { type: App.PLAY_PAUSE };
};

// local系
export const changeValueWithKey = (key, value) => ({
  type: App.CHANGE_VALUE_WITH_KEY, key, value,
});
export const changeTextWithACtive = (textType, text, flgType) => ({
  type: App.CHANGE_TEXT_WITH_ACTIVE, textType, text, flgType, value: text.length >= 1,
});
export const changeCommentText = (text) => ({
  type: App.CHANGE_COMMENT_TEXT, text, isCommentActive: text.length >= 1,
});
export const setUser = (user, isLogin) => ({ type: App.SET_USER, user, isLogin });
export const setDefaultUser = () => ({ type: App.SET_DEFAULT_USER });
export const changeVolume = (volume) => ({ type: App.CHANGE_VOLUME, volume });
export const setSearchResult = (result) => ({
  type: App.SET_SEARCH_RESULT,
  result: result.items.map((item) => ({
    videoId: item.id.videoId, title: item.snippet.title, thumbnail: item.snippet.thumbnails.default,
  })),
});
export const seekDown = () => ({ type: App.SEEK_DOWN });
export const seekUp = (played) => ({ type: App.SEEK_UP, played });
export const progress = (state) => {
  const { played, loaded } = state;
  const playingStatus = (state.loaded) ? { played, loaded } : { played };
  return { type: App.PROGRESS, playingStatus };
};
export const updateSyncState = (key, value) => ({ type: App.UPDATE_SYNC_STATE, key, value });
export const updateQue = (que) => ({ type: App.UPDATE_QUE, que });
export const updateComments = (comments) => ({ type: App.UPDATE_COMMENTS, comments });
export const updatePlayed = (played) => ({ type: App.UPDATE_PLAYED, played });
export const updatePlaying = (playing) => ({ type: App.UPDATE_PLAYING, playing });
export const updatePlayingVideo = (video) => {
  const playingVideo = Object.keys(video).length === 0 ? App.DefaultVideo : video;
  console.log(playingVideo);
  return { type: App.UPDATE_PLAYING_VIDEO, playingVideo };
};
<commit_msg>console.log<commit_after>import * as App from '../constants/app';
import { base } from '../config/firebaseApp.js';

const push = (stateName, data) => base.push(stateName, { data });
const post = (stateName, data) => base.post(stateName, { data });
const remove = (endPoint) => base.remove(endPoint);

// sync系
export const postPlayingVideo = (video) => {
  if (video) {
    post('playingVideo', video);
    post('startTime', 0);
  } else {
    post('playingVideo', {});
    post('startTime', 0);
  }
  return { type: App.POST_PLAYING_VIDEO };
};
export const pushVideo = (video) => {
  push('que', video);
  return { type: App.PUSH_VIDEO };
};
export const addComment = (comment) => {
  push('comments', comment);
  return { type: App.ADD_COMMENT };
};
export const removeVideo = (video) => {
  remove(`que/${video.key}`);
  return { type: App.REMOVE_VIDEO };
};
export const changePlayed = (played) => {
  post('startTime', played);
  return { type: App.CHANGE_PLAYED, played };
};
export const play = () => ({ type: App.PLAY });
export const pause = (startTime) => {
  post('startTime', startTime);
  return { type: App.PAUSE };
};
export const playPause = (isPlaying) => {
  const playing = !isPlaying;
  post('playing', playing);
  return { type: App.PLAY_PAUSE };
};

// local系
export const changeValueWithKey = (key, value) => ({
  type: App.CHANGE_VALUE_WITH_KEY, key, value,
});
export const changeTextWithACtive = (textType, text, flgType) => ({
  type: App.CHANGE_TEXT_WITH_ACTIVE, textType, text, flgType, value: text.length >= 1,
});
export const changeCommentText = (text) => ({
  type: App.CHANGE_COMMENT_TEXT, text, isCommentActive: text.length >= 1,
});
export const setUser = (user, isLogin) => ({ type: App.SET_USER, user, isLogin });
export const setDefaultUser = () => ({ type: App.SET_DEFAULT_USER });
export const changeVolume = (volume) => ({ type: App.CHANGE_VOLUME, volume });
export const setSearchResult = (result) => ({
  type: App.SET_SEARCH_RESULT,
  result: result.items.map((item) => ({
    videoId: item.id.videoId, title: item.snippet.title, thumbnail: item.snippet.thumbnails.default,
  })),
});
export const seekDown = () => ({ type: App.SEEK_DOWN });
export const seekUp = (played) => ({ type: App.SEEK_UP, played });
export const progress = (state) => {
  const { played, loaded } = state;
  const playingStatus = (state.loaded) ? { played, loaded } : { played };
  return { type: App.PROGRESS, playingStatus };
};
export const updateSyncState = (key, value) => ({ type: App.UPDATE_SYNC_STATE, key, value });
export const updateQue = (que) => ({ type: App.UPDATE_QUE, que });
export const updateComments = (comments) => ({ type: App.UPDATE_COMMENTS, comments });
export const updatePlayed = (played) => ({ type: App.UPDATE_PLAYED, played });
export const updatePlaying = (playing) => ({ type: App.UPDATE_PLAYING, playing });
export const updatePlayingVideo = (video) => {
  const playingVideo = Object.keys(video).length === 0 ? App.DefaultVideo : video;
  return { type: App.UPDATE_PLAYING_VIDEO, playingVideo };
};
<|endoftext|>


<commit_before>'use strict';
module.exports = function(app, db) {

  app.route('/latest')
    // Retrieve most recent searches
    .get(handleGet);

  app.get('/:query?offset=10', handlePost);

  function handleGet (req, res, db) {
      // Get and display latest searches
      var objArr;
      res.send(objArr);
  }

  function handlePost (req, res, db) {
      // Get images and save query and date.
      var results;
      res.send(results);
  }

};<commit_msg>Trying to connect to db<commit_after>'use strict';
module.exports = function(app, db) {

  app.route('/latest')
    // Retrieve most recent searches
    .get(handleGet);

  app.get('/:query', handlePost);

  function handleGet (req, res, db) {
      // Get and display latest searches
      getHistory(db, res);
  }

  function handlePost (req, res, db) {
      // Get images and save query and date.
      var ip = req.headers['x-forwarded-for'] ||
                 req.connection.remoteAddress ||
                 req.socket.remoteAddress ||
                 req.connection.socket.remoteAddress;
      var query = req.params.query;
      var size = req.query;
      var url = 'https://ajax.googleapis.com/ajax/services/search/imagesv=1.0&q=' + query + '&userip=' + ip + '&rsz=' + size.offset;
      var xmlhttp = new XMLHttpRequest();
      xmlhttp.onreadystatechange = function() {
          if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
              var results = JSON.parse(xmlhttp.responseText);
              res.send(results);
              save(results, db);
          }
      };
      xmlhttp.open("GET", url, true);
      xmlhttp.send();
  }

  function save(obj, db) {
    // Save object into db.
    var searches = db.collection('searches');
    searches.save(obj, function(err, result) {
      if (err) throw err;
      console.log('Saved ' + result);
    });
  }

  function getHistory(db, res) {
    // Check to see if the site is already there
    var searches = db.collection('searches');
    // get the url
    searches.find(function(err, result) {
      if (err) throw err;
      // object of the url
      if (result) {
        // we have a result
        console.log('Found ' + result);
        res.send(result);
      } else {
        // we don't
        res.send('No history Found');
      }
    });
  }

};<|endoftext|>


<commit_before>'use babel'
/*
 * decaffeinate suggestions:
 * DS102: Remove unnecessary code created because of implicit returns
 * DS207: Consider shorter variations of null checks
 * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
 */
import {Disposable} from 'atom';
import path from 'path';

const element_name = 'waka-status-bar' + Date.now();

const svg = `\
<svg id="wakatime-svg" width="18px" height="18px" viewBox="0 0 256 256" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
<g><path d="M128,0 C57.308,0 0,57.308 0,128 C0,198.693 57.308,256 128,256 C198.693,256 256,198.693 256,128 C256,57.308 198.693,0 128,0 M128,33.805 C179.939,33.805 222.195,76.061 222.195,128 C222.195,179.94 179.939,222.195 128,222.195 C76.061,222.195 33.805,179.94 33.805,128 C33.805,76.061 76.061,33.805 128,33.805 M115.4993,155.6431 L115.3873,155.6431 C113.4353,155.6081 111.6083,154.6751 110.4343,153.1151 L81.5593,114.7321 C79.4553,111.9351 80.0173,107.9611 82.8143,105.8561 C85.6123,103.7511 89.5853,104.3131 91.6903,107.1111 L115.6833,139.0051 L122.5463,130.5271 C123.7493,129.0411 125.5603,128.1771 127.4723,128.1771 L127.4803,128.1771 C129.3973,128.1791 131.2093,129.0471 132.4103,130.5411 L139.0003,138.7281 L176.6923,90.1341 C178.8353,87.3681 182.8173,86.8651 185.5843,89.0111 C188.3493,91.1561 188.8533,95.1371 186.7073,97.9041 L144.1003,152.8371 C142.9143,154.3681 141.0883,155.2721 139.1503,155.2901 L139.0933,155.2901 C137.1743,155.2901 135.3583,154.4221 134.1553,152.9261 L127.4583,144.6071 L120.4253,153.2931 C119.2213,154.7811 117.4103,155.6431 115.4993,155.6431" fill="#000000"></path></g>
</svg>\
`;
class StatusBarTileView extends HTMLElement {

  init() {
    this.link = document.createElement('a');
    this.link.classList.add('inline-block');
    this.link.href = 'https://wakatime.com/';
    this.appendChild(this.link);

    this.icon = document.createElement('div');
    this.icon.setAttribute('id', 'wakatime-status-bar');
    this.icon.classList.add('inline-block');
    this.icon.innerHTML = svg;
    this.link.appendChild(this.icon);

    this.msg = document.createElement('span');
    this.msg.classList.add('inline-block');
    this.link.appendChild(this.msg);

    return this.setStatus("initializing...");
  }

  show() {
    this.classList.add(element_name, 'inline-block');
    return this.classList.remove(element_name, 'hidden');
  }

  hide() {
    this.classList.remove(element_name, 'inline-block');
    return this.classList.add(element_name, 'hidden');
  }

  destroy() {
    if (this.tooltip != null) {
      this.tooltip.dispose();
    }
    return this.classList = '';
  }

  setStatus(content, override_errors) {
    if (override_errors == null) { override_errors = true; }
    if (override_errors || /^error/i.test((this.msg != null ? this.msg.textContent : undefined) || '')) {
      return (this.msg != null ? this.msg.textContent = content || '' : undefined);
    }
  }

  setTitle(text) {
    if (this.tooltip != null) {
      this.tooltip.dispose();
    }
    return this.tooltip = atom.tooltips.add(this,
      {title: text});
  }
}

export default statusBarElm = document.registerElement(element_name, {prototype: StatusBarTileView.prototype, extends: 'div'});
<commit_msg>Remove unused imports<commit_after>'use babel'
/*
 * decaffeinate suggestions:
 * DS102: Remove unnecessary code created because of implicit returns
 * DS207: Consider shorter variations of null checks
 * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
 */

const element_name = 'waka-status-bar' + Date.now();

const svg = `\
<svg id="wakatime-svg" width="18px" height="18px" viewBox="0 0 256 256" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
<g><path d="M128,0 C57.308,0 0,57.308 0,128 C0,198.693 57.308,256 128,256 C198.693,256 256,198.693 256,128 C256,57.308 198.693,0 128,0 M128,33.805 C179.939,33.805 222.195,76.061 222.195,128 C222.195,179.94 179.939,222.195 128,222.195 C76.061,222.195 33.805,179.94 33.805,128 C33.805,76.061 76.061,33.805 128,33.805 M115.4993,155.6431 L115.3873,155.6431 C113.4353,155.6081 111.6083,154.6751 110.4343,153.1151 L81.5593,114.7321 C79.4553,111.9351 80.0173,107.9611 82.8143,105.8561 C85.6123,103.7511 89.5853,104.3131 91.6903,107.1111 L115.6833,139.0051 L122.5463,130.5271 C123.7493,129.0411 125.5603,128.1771 127.4723,128.1771 L127.4803,128.1771 C129.3973,128.1791 131.2093,129.0471 132.4103,130.5411 L139.0003,138.7281 L176.6923,90.1341 C178.8353,87.3681 182.8173,86.8651 185.5843,89.0111 C188.3493,91.1561 188.8533,95.1371 186.7073,97.9041 L144.1003,152.8371 C142.9143,154.3681 141.0883,155.2721 139.1503,155.2901 L139.0933,155.2901 C137.1743,155.2901 135.3583,154.4221 134.1553,152.9261 L127.4583,144.6071 L120.4253,153.2931 C119.2213,154.7811 117.4103,155.6431 115.4993,155.6431" fill="#000000"></path></g>
</svg>\
`;
class StatusBarTileView extends HTMLElement {

  init() {
    this.link = document.createElement('a');
    this.link.classList.add('inline-block');
    this.link.href = 'https://wakatime.com/';
    this.appendChild(this.link);

    this.icon = document.createElement('div');
    this.icon.setAttribute('id', 'wakatime-status-bar');
    this.icon.classList.add('inline-block');
    this.icon.innerHTML = svg;
    this.link.appendChild(this.icon);

    this.msg = document.createElement('span');
    this.msg.classList.add('inline-block');
    this.link.appendChild(this.msg);

    return this.setStatus("initializing...");
  }

  show() {
    this.classList.add(element_name, 'inline-block');
    return this.classList.remove(element_name, 'hidden');
  }

  hide() {
    this.classList.remove(element_name, 'inline-block');
    return this.classList.add(element_name, 'hidden');
  }

  destroy() {
    if (this.tooltip != null) {
      this.tooltip.dispose();
    }
    return this.classList = '';
  }

  setStatus(content, override_errors) {
    if (override_errors == null) { override_errors = true; }
    if (override_errors || /^error/i.test((this.msg != null ? this.msg.textContent : undefined) || '')) {
      return (this.msg != null ? this.msg.textContent = content || '' : undefined);
    }
  }

  setTitle(text) {
    if (this.tooltip != null) {
      this.tooltip.dispose();
    }
    return this.tooltip = atom.tooltips.add(this,
      {title: text});
  }
}

export default statusBarElm = document.registerElement(element_name, {prototype: StatusBarTileView.prototype, extends: 'div'});
<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
'use strict';
var safeParse = require('../util').safeParse;
var TypedError = require('error/typed');

var BadPingReqPingStatusError = TypedError({
    type: 'ringpop.ping-req.bad-ping-status',
    message: 'Bad ping status from ping-req ping: {pingStatus}',
    selected: null,
    target: null,
    pingStatus: null
});

var BadPingReqRespBodyError = TypedError({
    type: 'ringpop.ping-req.bad-resp-body',
    message: 'Bad response from ping-req: {body}',
    selected: null,
    target: null,
    body: null
});

var NoMembersError = TypedError({
    type: 'ringpop.ping-req.no-members',
    message: 'No selectable ping-req members'
});

var PingReqInconclusiveError = TypedError({
    type: 'ringpop.ping-req.inconclusive',
    message: 'Ping-req is inconclusive'
});

var PingReqPingError = TypedError({
    type: 'ringpop.ping-req.ping',
    message: 'An error occurred on ping-req ping: {errMessage}',
    errMessage: null
});

function body(sender) {
    return JSON.stringify({
        checksum: sender.ring.membership.checksum,
        changes: sender.ring.dissemination.issueChanges(),
        source: sender.ring.whoami(),
        target: sender.target.address
    });
}

function sendOptions(sender)  {
    return {
        host: sender.member.address,
        timeout: sender.ring.pingReqTimeout
    };
}

function PingReqSender(ring, member, target, callback) {
    this.ring = ring;
    this.member = member;
    this.target = target;
    this.callback = callback;
}

PingReqSender.prototype.send = function send() {
    var self = this;

    this.ring.channel.send(sendOptions(this), '/protocol/ping-req', null, body(this), onSend);

    function onSend(err, res1, res2) {
        self.onPingReq(err, res1, res2);
    }
};

PingReqSender.prototype.onPingReq = function (err, res1, res2) {
    if (err) {
        this.ring.logger.warn('bad response to ping-req from ' + this.member.address + ' err=' + err.message);
        this.callback(PingReqPingError({
            errMessage: err.message
        }));
        return;
    }

    var res2Str = res2.toString();
    var bodyObj = safeParse(res2Str);
    if (! bodyObj || !bodyObj.changes || bodyObj.pingStatus === 'undefined') {
        this.ring.logger.warn('bad response body in ping-req from ' + this.member.address);
        this.callback(BadPingReqRespBodyError({
            selected: this.member.address,
            target: this.target.address,
            body: res2Str
        }));
        return;
    }

    this.ring.membership.update(bodyObj.changes);
    this.ring.debugLog('ping-req recv peer=' + this.member.address + ' target=' + this.target.address + ' isOk=' + bodyObj.pingStatus);

    if (!bodyObj.pingStatus) {
        this.callback(BadPingReqPingStatusError({
            selected: this.member.address,
            target: this.target.address,
            pingStatus: bodyObj.pingStatus
        }));
        return;
    }

    this.callback();
};

module.exports = function sendPingReq(opts, callback) {
    var ringpop = opts.ringpop;
    var unreachableMember = opts.unreachableMember;
    var pingReqSize = opts.pingReqSize;

    ringpop.stat('increment', 'ping-req.send');

    var pingReqMembers = randomMembers();
    ringpop.stat('timing', 'ping-req.other-members', pingReqMembers.length);

    if (pingReqMembers.length === 0) {
        callback(NoMembersError());
        return;
    }

    var addrs = pingReqAddrs(pingReqMembers);
    var calledBack = false;
    var errors = [];
    var startTime = Date.now();
    var unreachableMemberInfo = {
        address: unreachableMember.address,
        startingStatus: unreachableMember.status
    };

    for (var i = 0; i < pingReqMembers.length; i++) {
        var pingReqMember = pingReqMembers[i];

        // TODO Cleanup this log site
        ringpop.debugLog('ping-req send peer=' + pingReqMember.address +
            ' target=' + unreachableMember.address, 'p');

        var sender = new PingReqSender(ringpop, pingReqMember, unreachableMember,
            onPingReqHandler(pingReqMember, pingReqMember.status));
        sender.send();
    }

    function onPingReqHandler(pingReqMember, startingStatus) {
        return function onPingReq(err) {
            if (calledBack) {
                return;
            }

            var pingReqMemberInfo = {
                address: pingReqMember.address,
                startingStatus: startingStatus,
                endingStatus: pingReqMember.status
            };

            // NOTE If the member is reachable, we don't explicitly
            // mark the unreachable member alive here. It happens
            // through implicit exchange of membership updates on
            // ping-req requests and responses.
            if (!err) {
                ringpop.logger.info('ringpop ping-req determined member is reachable', {
                    local: ringpop.whoami(),
                    errors: errors,
                    numErrors: errors.length,
                    numPingReqMembers: pingReqMembers.length,
                    pingReqAddrs: addrs,
                    pingReqMemberInfo: pingReqMemberInfo,
                    totalPingReqTime: Date.now() - startTime,
                    unreachableMemberInfo: unreachableMemberInfo
                });

                calledBack = true;
                callback(null, {
                    pingReqAddrs: addrs,
                    pingReqSuccess: pingReqMemberInfo
                });
                return;
            }

            errors.push(err);

            if (errors.length < pingReqMembers.length) {
                // Keep waiting for responses...
                return;
            }

            // A ping-req request may result in many types of errors.
            // The only ones that should count against the unreachable
            // member are those that have a valid response from a
            // chosen ping-req member that also could not reach that
            // member. If all errors are of that type, then make the
            // unreachable member a suspect.
            var numPingReqStatusErrs = 0;

            for (var i = 0; i < errors.length; i++) {
                var error = errors[i];

                if (error.type === 'ringpop.ping-req.bad-ping-status') {
                    numPingReqStatusErrs++;
                }
            }

            if (numPingReqStatusErrs > 0) {
                ringpop.logger.warn('ringpop ping-req determined member is unreachable', {
                    local: ringpop.whoami(),
                    errors: errors,
                    numErrors: errors.length,
                    numPingReqMembers: pingReqMembers.length,
                    numPingReqStatusErrs: numPingReqStatusErrs,
                    pingReqAddrs: addrs,
                    totalPingReqTime: Date.now() - startTime,
                    unreachableMemberInfo: unreachableMemberInfo
                });

                ringpop.membership.makeSuspect(unreachableMember.address,
                    unreachableMember.incarnationNumber);

                calledBack = true;
                callback(null, {
                    pingReqAddrs: addrs,
                    pingReqErrs: errors
                });
            } else {
                ringpop.logger.warn('ringpop ping-req inconclusive due to errors', {
                    local: ringpop.whoami(),
                    errors: errors,
                    numErrors: errors.length,
                    numPingReqMembers: pingReqMembers.length,
                    numPingReqStatusErrs: numPingReqStatusErrs,
                    pingReqAddrs: addrs,
                    totalPingReqTime: Date.now() - startTime,
                    unreachableMemberInfo: unreachableMemberInfo
                });

                calledBack = true;
                callback(PingReqInconclusiveError());
            }
        };
    }

    function pingReqAddrs(pingReqMembers) {
        return pingReqMembers.map(function mapMember(member) {
            return member.address;
        });
    }

    function randomMembers() {
        return ringpop.membership.getRandomPingableMembers(
            pingReqSize, [unreachableMember.address]);
    }
};
<commit_msg>remove dynamic log messages<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
'use strict';
var safeParse = require('../util').safeParse;
var TypedError = require('error/typed');

var BadPingReqPingStatusError = TypedError({
    type: 'ringpop.ping-req.bad-ping-status',
    message: 'Bad ping status from ping-req ping: {pingStatus}',
    selected: null,
    target: null,
    pingStatus: null
});

var BadPingReqRespBodyError = TypedError({
    type: 'ringpop.ping-req.bad-resp-body',
    message: 'Bad response from ping-req: {body}',
    selected: null,
    target: null,
    body: null
});

var NoMembersError = TypedError({
    type: 'ringpop.ping-req.no-members',
    message: 'No selectable ping-req members'
});

var PingReqInconclusiveError = TypedError({
    type: 'ringpop.ping-req.inconclusive',
    message: 'Ping-req is inconclusive'
});

var PingReqPingError = TypedError({
    type: 'ringpop.ping-req.ping',
    message: 'An error occurred on ping-req ping: {errMessage}',
    errMessage: null
});

function body(sender) {
    return JSON.stringify({
        checksum: sender.ring.membership.checksum,
        changes: sender.ring.dissemination.issueChanges(),
        source: sender.ring.whoami(),
        target: sender.target.address
    });
}

function sendOptions(sender)  {
    return {
        host: sender.member.address,
        timeout: sender.ring.pingReqTimeout
    };
}

function PingReqSender(ring, member, target, callback) {
    this.ring = ring;
    this.member = member;
    this.target = target;
    this.callback = callback;
}

PingReqSender.prototype.send = function send() {
    var self = this;

    this.ring.channel.send(sendOptions(this), '/protocol/ping-req', null, body(this), onSend);

    function onSend(err, res1, res2) {
        self.onPingReq(err, res1, res2);
    }
};

PingReqSender.prototype.onPingReq = function (err, res1, res2) {
    if (err) {
        this.ring.logger.warn('bad response to ping-req', {
            address: this.member.address,
            err: err
        });
        this.callback(PingReqPingError({
            errMessage: err.message
        }));
        return;
    }

    var res2Str = res2.toString();
    var bodyObj = safeParse(res2Str);
    if (! bodyObj || !bodyObj.changes || bodyObj.pingStatus === 'undefined') {
        this.ring.logger.warn('bad response body in ping-req', {
            address: this.member.address
        });
        this.callback(BadPingReqRespBodyError({
            selected: this.member.address,
            target: this.target.address,
            body: res2Str
        }));
        return;
    }

    this.ring.membership.update(bodyObj.changes);
    this.ring.debugLog('ping-req recv peer=' + this.member.address + ' target=' + this.target.address + ' isOk=' + bodyObj.pingStatus);

    if (!bodyObj.pingStatus) {
        this.callback(BadPingReqPingStatusError({
            selected: this.member.address,
            target: this.target.address,
            pingStatus: bodyObj.pingStatus
        }));
        return;
    }

    this.callback();
};

module.exports = function sendPingReq(opts, callback) {
    var ringpop = opts.ringpop;
    var unreachableMember = opts.unreachableMember;
    var pingReqSize = opts.pingReqSize;

    ringpop.stat('increment', 'ping-req.send');

    var pingReqMembers = randomMembers();
    ringpop.stat('timing', 'ping-req.other-members', pingReqMembers.length);

    if (pingReqMembers.length === 0) {
        callback(NoMembersError());
        return;
    }

    var addrs = pingReqAddrs(pingReqMembers);
    var calledBack = false;
    var errors = [];
    var startTime = Date.now();
    var unreachableMemberInfo = {
        address: unreachableMember.address,
        startingStatus: unreachableMember.status
    };

    for (var i = 0; i < pingReqMembers.length; i++) {
        var pingReqMember = pingReqMembers[i];

        // TODO Cleanup this log site
        ringpop.debugLog('ping-req send peer=' + pingReqMember.address +
            ' target=' + unreachableMember.address, 'p');

        var sender = new PingReqSender(ringpop, pingReqMember, unreachableMember,
            onPingReqHandler(pingReqMember, pingReqMember.status));
        sender.send();
    }

    function onPingReqHandler(pingReqMember, startingStatus) {
        return function onPingReq(err) {
            if (calledBack) {
                return;
            }

            var pingReqMemberInfo = {
                address: pingReqMember.address,
                startingStatus: startingStatus,
                endingStatus: pingReqMember.status
            };

            // NOTE If the member is reachable, we don't explicitly
            // mark the unreachable member alive here. It happens
            // through implicit exchange of membership updates on
            // ping-req requests and responses.
            if (!err) {
                ringpop.logger.info('ringpop ping-req determined member is reachable', {
                    local: ringpop.whoami(),
                    errors: errors,
                    numErrors: errors.length,
                    numPingReqMembers: pingReqMembers.length,
                    pingReqAddrs: addrs,
                    pingReqMemberInfo: pingReqMemberInfo,
                    totalPingReqTime: Date.now() - startTime,
                    unreachableMemberInfo: unreachableMemberInfo
                });

                calledBack = true;
                callback(null, {
                    pingReqAddrs: addrs,
                    pingReqSuccess: pingReqMemberInfo
                });
                return;
            }

            errors.push(err);

            if (errors.length < pingReqMembers.length) {
                // Keep waiting for responses...
                return;
            }

            // A ping-req request may result in many types of errors.
            // The only ones that should count against the unreachable
            // member are those that have a valid response from a
            // chosen ping-req member that also could not reach that
            // member. If all errors are of that type, then make the
            // unreachable member a suspect.
            var numPingReqStatusErrs = 0;

            for (var i = 0; i < errors.length; i++) {
                var error = errors[i];

                if (error.type === 'ringpop.ping-req.bad-ping-status') {
                    numPingReqStatusErrs++;
                }
            }

            if (numPingReqStatusErrs > 0) {
                ringpop.logger.warn('ringpop ping-req determined member is unreachable', {
                    local: ringpop.whoami(),
                    errors: errors,
                    numErrors: errors.length,
                    numPingReqMembers: pingReqMembers.length,
                    numPingReqStatusErrs: numPingReqStatusErrs,
                    pingReqAddrs: addrs,
                    totalPingReqTime: Date.now() - startTime,
                    unreachableMemberInfo: unreachableMemberInfo
                });

                ringpop.membership.makeSuspect(unreachableMember.address,
                    unreachableMember.incarnationNumber);

                calledBack = true;
                callback(null, {
                    pingReqAddrs: addrs,
                    pingReqErrs: errors
                });
            } else {
                ringpop.logger.warn('ringpop ping-req inconclusive due to errors', {
                    local: ringpop.whoami(),
                    errors: errors,
                    numErrors: errors.length,
                    numPingReqMembers: pingReqMembers.length,
                    numPingReqStatusErrs: numPingReqStatusErrs,
                    pingReqAddrs: addrs,
                    totalPingReqTime: Date.now() - startTime,
                    unreachableMemberInfo: unreachableMemberInfo
                });

                calledBack = true;
                callback(PingReqInconclusiveError());
            }
        };
    }

    function pingReqAddrs(pingReqMembers) {
        return pingReqMembers.map(function mapMember(member) {
            return member.address;
        });
    }

    function randomMembers() {
        return ringpop.membership.getRandomPingableMembers(
            pingReqSize, [unreachableMember.address]);
    }
};
<|endoftext|>


<commit_before>"use strict";

var boxIntersect = require("box-intersect");

module.exports = function(ecs, game) {

	game.entities.registerSearch("boxCollider", ["position", "size", "collisions"]);

	var boxPool = [];
	var boxPoolLength = 0;
	function growBoxPool(size) {
		boxPoolLength = size;
		while (boxPool.length < size) {
			for (var i = 0; i < 50; i++) {
				boxPool.push([0, 0, 0, 0]);
			}
		}
	}

	ecs.add(function boxCollider(entities, elapsed) { // eslint-disable-line no-unused-vars
		var ids = game.entities.find("boxCollider");

		growBoxPool(ids.length);
		ids.forEach(function(entity, i) {
			game.entities.get(entity, "collisions").length = 0;
			var position = game.entities.get(entity, "position");
			var size = game.entities.get(entity, "size");
			boxPool[i][0] = position.x;
			boxPool[i][1] = position.y;
			boxPool[i][2] = position.x + size.width;
			boxPool[i][3] = position.y + size.height;
		});
		boxIntersect(boxPool, function(a, b) {
			if (a >= boxPoolLength || b >= boxPoolLength) {
				return;
			}
			var idA = ids[a];
			var idB = ids[b];
			game.entities.get(idA, "collisions").push(idB);
			game.entities.get(idB, "collisions").push(idA);
		});
	});
};
<commit_msg>remove deleted entities from collision lists<commit_after>"use strict";

var boxIntersect = require("box-intersect");

module.exports = function(ecs, game) {

	game.entities.registerSearch("boxCollider", ["position", "size", "collisions"]);

	game.entities.onRemoveComponent("collisions", function(entity, component, collisions) {
		for (var i = 0; i < collisions.length; i++) {
			var otherCollisions = game.entities.get(collisions[i], "collisions");
			var idx = otherCollisions.indexOf(entity);
			if (idx !== -1) {
				otherCollisions.splice(idx,1);
			}
		}
	});

	var boxPool = [];
	var boxPoolLength = 0;
	function growBoxPool(size) {
		boxPoolLength = size;
		while (boxPool.length < size) {
			for (var i = 0; i < 50; i++) {
				boxPool.push([0, 0, 0, 0]);
			}
		}
	}

	ecs.add(function boxCollider(entities, elapsed) { // eslint-disable-line no-unused-vars
		var ids = game.entities.find("boxCollider");

		growBoxPool(ids.length);
		ids.forEach(function(entity, i) {
			game.entities.get(entity, "collisions").length = 0;
			var position = game.entities.get(entity, "position");
			var size = game.entities.get(entity, "size");
			boxPool[i][0] = position.x;
			boxPool[i][1] = position.y;
			boxPool[i][2] = position.x + size.width;
			boxPool[i][3] = position.y + size.height;
		});
		boxIntersect(boxPool, function(a, b) {
			if (a >= boxPoolLength || b >= boxPoolLength) {
				return;
			}
			var idA = ids[a];
			var idB = ids[b];
			game.entities.get(idA, "collisions").push(idB);
			game.entities.get(idB, "collisions").push(idA);
		});
	});
};
<|endoftext|>


<commit_before>import { isEmpty, toUpper, forOwn, omit, toNumber, isFinite } from 'lodash';
import validator from 'validator';
import DataType from '../data-types';
import Util, { isNullOrUndefined, isDefined } from '../util';

const createError = error => ({ result: false, error });

const isLessThanMinValue = (value, minValue) => {
  if (isNullOrUndefined(minValue)) {
    return false;
  }

  if (isNullOrUndefined(value)) {
    return true;
  } else if (value < minValue) {
    return true;
  }
  return false;
};

const isGreaterThanMaxValue = (value, maxValue) => {
  if (isNullOrUndefined(maxValue)) {
    return false;
  }

  if (isNullOrUndefined(value)) {
    return true;
  } else if (value > maxValue) {
    return true;
  }
  return false;
};

const isValid = (text, validatorToUse) => {
  if (!validatorToUse) {
    return true;
  }

  if (!isEmpty(text) && !validator[validatorToUse](`${text}`)) {
    return false;
  }
  return true;
}

const isValidRegex = (text, validationRegex) => {
  if (isNullOrUndefined(text) || isNullOrUndefined(validationRegex)) {
    return true;
  }
  const pattern = new RegExp(validationRegex);
  const response = text.match(pattern);
  if (!response) {
    return false;
  }
  return true;
};

export function isFormValid(form) {
  const formFields = omit(form, 'schema', 'valid');
  let valid = true;
  forOwn(formFields, (value) => {
    valid = valid && (value && value.validationResult ? value.validationResult.result : false);
  });
  return valid;
}

export function validateDataAgainstSchema(name, value, schema) {
  if (isNullOrUndefined(schema)) {
    return { result: true };
  }

  switch (toUpper(schema.fieldType)) {
    case DataType.Any:
      if (schema.isRequired && (isNullOrUndefined(value) || isEmpty(value))) {
        return {
          result: false,
          error: '*Required',
        };
      }
      return { result: true };
    case DataType.String:
      if (schema.isRequired && (isNullOrUndefined(value) || isEmpty(value))) {
        return {
          result: false,
          error: '*Required',
        };
      }

      if (!isValid(value, schema.validatorType)) {
        return createError('*Invalid value');
      }

      if (!isValidRegex(value, schema.validationRegex)) {
        return createError('*Invalid value');
      }
      return { result: true };
    case DataType.Number:
      if (schema.isRequired) {
        if(isNullOrUndefined(value)) {
          return {
            result: false,
            error: '*Required',
          };
        }

        if (typeof value === 'string') {
          if (isEmpty(value)) {
            return {
              result: false,
              error: '*Required',
            };
          }

          const numberVal = toNumber(value);
          if (!isFinite(numberVal)) {
            return {
              result: false,
              error: '*Required',
            };
          }
        } else if (typeof value !== 'number') {
          return {
            result: false,
            error: '*Required',
          };
        }
      }

      if (!isValid(value, 'isDecimal')) {
        return { result: false, error: '*Invalid value type'};
      }

      if (isLessThanMinValue(value, schema.minValue)) {
        return { result: false, error: '*Invalid value' };
      }

      if (isGreaterThanMaxValue(value, schema.maxValue)) {
        return { result: false, error: '*Invalid value' };
      }
      return { result: true };
    case DataType.Date:
      if (schema.isRequired && isNullOrUndefined(value)) {
        return {
          result: false,
          error: '*Required',
        };
      }
      return { result: true };
    case DataType.Time:
      if (schema.isRequired && isNullOrUndefined(value)) {
        return {
          result: false,
          error: '*Required',
        };
      }
      return { result: true };
    default:
      return { result: true };
  }
}

export function validateSingleField(name, value, schema) {
  let fieldValue = value;
  if (isNullOrUndefined(schema)) {
    return null;
  }

  if (isNullOrUndefined(value) && isDefined(schema.defaultValue)) {
    fieldValue = schema.defaultValue;
  }

  // If the field is array type than initialize it to an empty Array
  // if value is null or undefined.
  if (toUpper(schema.fieldType) === DataType.Array && isNullOrUndefined(fieldValue)) {
    fieldValue = [];
  }

  const validationResult = validateDataAgainstSchema(name, fieldValue, schema);

  // Apply decimal places to the number
  if (validationResult.result && (toUpper(schema.fieldType) === DataType.Number)) {
    if (typeof fieldValue === 'string' && !isEmpty(fieldValue) && isFinite(toNumber(fieldValue))) {
      fieldValue = Util.fixDouble(toNumber(fieldValue), schema.decimalPlaces);
    }
  }
  return { value: fieldValue, validationResult: { ...validationResult } };
}

export function validateObject(data, schema) {
  const outputData = {};
  forOwn(schema, (value, key) => {
    const retValue = validateSingleField(key, data[key], value);
    if (isDefined(retValue)) {
      outputData[key] = retValue;
    }
  });

  return outputData;
}
<commit_msg>Added validation for array datatype<commit_after>import { isEmpty, toUpper, forOwn, omit, toNumber, isFinite } from 'lodash';
import validator from 'validator';
import DataType from '../data-types';
import Util, { isNullOrUndefined, isDefined } from '../util';

const createError = error => ({ result: false, error });

const isLessThanMinValue = (value, minValue) => {
  if (isNullOrUndefined(minValue)) {
    return false;
  }

  if (isNullOrUndefined(value)) {
    return true;
  } else if (value < minValue) {
    return true;
  }
  return false;
};

const isGreaterThanMaxValue = (value, maxValue) => {
  if (isNullOrUndefined(maxValue)) {
    return false;
  }

  if (isNullOrUndefined(value)) {
    return true;
  } else if (value > maxValue) {
    return true;
  }
  return false;
};

const isValid = (text, validatorToUse) => {
  if (!validatorToUse) {
    return true;
  }

  if (!isEmpty(text) && !validator[validatorToUse](`${text}`)) {
    return false;
  }
  return true;
};

const isValidRegex = (text, validationRegex) => {
  if (isNullOrUndefined(text) || isNullOrUndefined(validationRegex)) {
    return true;
  }
  const pattern = new RegExp(validationRegex);
  const response = text.match(pattern);
  if (!response) {
    return false;
  }
  return true;
};

export function isFormValid(form) {
  const formFields = omit(form, 'schema', 'valid');
  let valid = true;
  forOwn(formFields, (value) => {
    valid = valid && (value && value.validationResult ? value.validationResult.result : false);
  });
  return valid;
}

export function validateDataAgainstSchema(name, value, schema) {
  if (isNullOrUndefined(schema)) {
    return { result: true };
  }

  switch (toUpper(schema.fieldType)) {
    case DataType.Any:
      if (schema.isRequired && (isNullOrUndefined(value) || isEmpty(value))) {
        return {
          result: false,
          error: '*Required',
        };
      }
      return { result: true };
    case DataType.String:
      if (schema.isRequired && (isNullOrUndefined(value) || isEmpty(value))) {
        return {
          result: false,
          error: '*Required',
        };
      }

      if (!isValid(value, schema.validatorType)) {
        return createError('*Invalid value');
      }

      if (!isValidRegex(value, schema.validationRegex)) {
        return createError('*Invalid value');
      }
      return { result: true };
    case DataType.Number:
      if (schema.isRequired) {
        if (isNullOrUndefined(value)) {
          return {
            result: false,
            error: '*Required',
          };
        }

        if (typeof value === 'string') {
          if (isEmpty(value)) {
            return {
              result: false,
              error: '*Required',
            };
          }

          const numberVal = toNumber(value);
          if (!isFinite(numberVal)) {
            return {
              result: false,
              error: '*Required',
            };
          }
        } else if (typeof value !== 'number') {
          return {
            result: false,
            error: '*Required',
          };
        }
      }

      if (!isValid(value, 'isDecimal')) {
        return { result: false, error: '*Invalid value type' };
      }

      if (isLessThanMinValue(value, schema.minValue)) {
        return { result: false, error: '*Invalid value' };
      }

      if (isGreaterThanMaxValue(value, schema.maxValue)) {
        return { result: false, error: '*Invalid value' };
      }
      return { result: true };
    case DataType.Date:
      if (schema.isRequired && isNullOrUndefined(value)) {
        return {
          result: false,
          error: '*Required',
        };
      }
      return { result: true };
    case DataType.Array:
      if (schema.isRequired && (isNullOrUndefined(value) || value.length === 0)) {
        return {
          result: false,
          error: '*Required',
        };
      }
      return { result: true };
    case DataType.Time:
      if (schema.isRequired && isNullOrUndefined(value)) {
        return {
          result: false,
          error: '*Required',
        };
      }
      return { result: true };
    default:
      return { result: true };
  }
}

export function validateSingleField(name, value, schema) {
  let fieldValue = value;
  if (isNullOrUndefined(schema)) {
    return null;
  }

  if (isNullOrUndefined(value) && isDefined(schema.defaultValue)) {
    fieldValue = schema.defaultValue;
  }

  // If the field is array type than initialize it to an empty Array
  // if value is null or undefined.
  if (toUpper(schema.fieldType) === DataType.Array && isNullOrUndefined(fieldValue)) {
    fieldValue = [];
  }

  const validationResult = validateDataAgainstSchema(name, fieldValue, schema);

  // Apply decimal places to the number
  if (validationResult.result && (toUpper(schema.fieldType) === DataType.Number)) {
    if (typeof fieldValue === 'string' && !isEmpty(fieldValue) && isFinite(toNumber(fieldValue))) {
      fieldValue = Util.fixDouble(toNumber(fieldValue), schema.decimalPlaces);
    }
  }
  return { value: fieldValue, validationResult: { ...validationResult } };
}

export function validateObject(data, schema) {
  const outputData = {};
  forOwn(schema, (value, key) => {
    const retValue = validateSingleField(key, data[key], value);
    if (isDefined(retValue)) {
      outputData[key] = retValue;
    }
  });

  return outputData;
}
<|endoftext|>


<commit_before>import * as ActionTypes from '../actions'
import merge from 'lodash/merge'
import uniq from 'lodash/uniq'

export const metadataReducer = (state = {}, action) => {
  let copyState

  if (action.response) {
    switch (action.type) {
      case ActionTypes.COUNT_SUCCESS:
      case ActionTypes.METADATA_SUCCESS:
      case ActionTypes.MIGRATION_SUCCESS:
        return merge({}, state, action.response)
      // remove - move to table and chart objects
      case ActionTypes.DATA_SUCCESS:
        let merged = merge({}, state, action.response)
        if (action.response.query) {
          merged.query.data = action.response.query.data
        } else {
          merged.table.data = action.response.table.data
        }
        return Object.assign({}, state, merged)
      default:
        return state
    }
  }

  switch (action.type) {
    case ActionTypes.LOAD_TABLE:
      return merge({}, state, {
        table: {
          tablePage: 0,
          isFetching: true
        }
      })
    case ActionTypes.UPDATE_PAGE:
      return merge({}, state, {
        table: {
          tablePage: action.page
        }
      })
    // move to table
    case ActionTypes.SORT_COLUMN:
      let updatedState = {
        table: {
          sorted: state.table.sorted ? uniq([action.key].concat(state.table.sorted)) : [action.key]
        },
        columns: {
          [action.key]: {
            sortDir: action.dir
          }
        }
      }
      return merge({}, state, updatedState)
    case ActionTypes.SELECT_COLUMN:
      let updatedQuery = {
        query: {
          isFetching: true,
          selectedColumn: action.payload
        }
      }
      if (state.query.groupBy === action.column) {
        updatedQuery.query.groupBy = null
      }
      return merge({}, state, updatedQuery)
    case ActionTypes.GROUP_BY:
      let groupKey = action.payload ? action.payload.value : null
      return merge({}, state, {
        query: {
          groupBy: groupKey
        }
      })
    case ActionTypes.SUM_BY:
      let sumKey = action.payload ? action.payload.value : null
      return merge({}, state, {
        query: {
          sumBy: sumKey
        }
      })
    case ActionTypes.CHANGE_DATEBY:
      return merge({}, state, {
        query: {
          dateBy: action.payload
        }
      })
    case ActionTypes.ADD_FILTER:
      return merge({}, state, {
        query: {
          filters: {
            [action.payload.value]: {}
          }
        }
      })
    case ActionTypes.APPLY_CHART_TYPE:
      return merge({}, state, {
        query: {
          chartType: action.chartType
        }
      })
    case ActionTypes.REMOVE_FILTER:
      copyState = {...state}
      delete copyState.query.filters[action.payload]
      return merge({}, state, copyState)
    case ActionTypes.UPDATE_FILTER:
      let newOptions = action.payload.options
      copyState = Object.assign({}, state)
      let existingOptions = copyState.query.filters[action.payload.key].options || ''
      let isSelected = (newOptions.selected)
      let newState

      if (isSelected && Array.isArray(existingOptions.selected) &&
        (existingOptions.selected.length !== newOptions.selected.length || typeof newOptions.selected === 'string')) {
        copyState.query.filters[action.payload.key].options.selected = action.payload.options.selected
        newState = merge({}, copyState)
      } else {
        let updatedOptions = {
          query: {
            filters: {
              [action.payload.key]: {
                options: action.payload.options
              }
            }
          }
        }
        newState = merge({}, state, updatedOptions)
      }
      return newState
    default:
      return state

  }
}
<commit_msg>remove cruft from metadataReducer<commit_after>import * as ActionTypes from '../actions'
import merge from 'lodash/merge'
import uniq from 'lodash/uniq'

export const metadataReducer = (state = {}, action) => {

  if (action.response) {
    switch (action.type) {
      case ActionTypes.COUNT_SUCCESS:
      case ActionTypes.METADATA_SUCCESS:
      case ActionTypes.MIGRATION_SUCCESS:
        return merge({}, state, action.response)
      default:
        return state
    }
  }

  switch (action.type) {
    default:
      return state

  }
}
<|endoftext|>


<commit_before>'use strict';

const log4js = require('log4js');
const clientLogger = log4js.getLogger('client');
const formidable = require('formidable');
const apiHandler = require('../../handler/APIHandler');

exports.expressCreateServer = (hookName, args, cb) => {
  // The Etherpad client side sends information about how a disconnect happened
  args.app.post('/ep/pad/connection-diagnostic-info', (req, res) => {
    new formidable.IncomingForm().parse(req, (err, fields, files) => {
      clientLogger.info(`DIAGNOSTIC-INFO: ${fields.diagnosticInfo}`);
      res.end('OK');
    });
  });

  // The Etherpad client side sends information about client side javscript errors
  args.app.post('/jserror', (req, res) => {
    new formidable.IncomingForm().parse(req, (err, fields, files) => {
      let data;
      try {
        data = JSON.parse(fields.errorInfo);
      } catch (e) {
        return res.end();
      }
      clientLogger.warn(`${data.msg} --`, data);
      res.end('OK');
    });
  });

  // Provide a possibility to query the latest available API version
  args.app.get('/api', (req, res) => {
    res.json({currentVersion: apiHandler.latestApiVersion});
  });

  return cb();
};
<commit_msg>/jserror: Refactor to handle errors better<commit_after>'use strict';

const log4js = require('log4js');
const clientLogger = log4js.getLogger('client');
const formidable = require('formidable');
const apiHandler = require('../../handler/APIHandler');

exports.expressCreateServer = (hookName, args, cb) => {
  // The Etherpad client side sends information about how a disconnect happened
  args.app.post('/ep/pad/connection-diagnostic-info', (req, res) => {
    new formidable.IncomingForm().parse(req, (err, fields, files) => {
      clientLogger.info(`DIAGNOSTIC-INFO: ${fields.diagnosticInfo}`);
      res.end('OK');
    });
  });

  const parseJserrorForm = async (req) => await new Promise((resolve, reject) => {
    const form = new formidable.IncomingForm();
    form.on('error', (err) => reject(err));
    form.parse(req, (err, fields) => err != null ? reject(err) : resolve(fields.errorInfo));
  });

  // The Etherpad client side sends information about client side javscript errors
  args.app.post('/jserror', (req, res, next) => {
    (async () => {
      const data = JSON.parse(await parseJserrorForm(req));
      clientLogger.warn(`${data.msg} --`, data);
      res.end('OK');
    })().catch((err) => next(err || new Error(err)));
  });

  // Provide a possibility to query the latest available API version
  args.app.get('/api', (req, res) => {
    res.json({currentVersion: apiHandler.latestApiVersion});
  });

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


<commit_before>goog.provide('ol.ellipsoid.WGS84');

goog.require('ol.Ellipsoid');

/**
 * @const
 * @type {ol.Ellipsoid}
 */
ol.ellipsoid.WGS84 = new ol.Ellipsoid(6378137, 1 / 298.257223563);
<commit_msg>Remove unused ol.ellipsoid.WGS84<commit_after><|endoftext|>


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

export class ReactCanvasSimple extends Component {

  static propTypes = {
    surfaceWidth: PropTypes.number,
    surfaceHeight: PropTypes.number,
    nodes: PropTypes.array
  };

  makeDiagram() {
    let $ = go.GraphObject.make;

    let myDiagram =
      $(go.Diagram, "myDiagramDiv",
        {
          initialContentAlignment: go.Spot.Center, // center Diagram contents
          "undoManager.isEnabled": true, // enable Ctrl-Z to undo and Ctrl-Y to redo
          layout: $(go.TreeLayout, // specify a Diagram.layout that arranges trees
                    { angle: 90, layerSpacing: 35 })
        });

    // the template we defined earlier
    myDiagram.nodeTemplate =
      $(go.Node, "Horizontal",
        { background: "#44CCFF" },
        $(go.TextBlock, "Default Text",
          { margin: 12, stroke: "white", font: "bold 16px sans-serif" },
          new go.Binding("text", "name"))
      );

    // define a Link template that routes orthogonally, with no arrowhead
    myDiagram.linkTemplate =
      $(go.Link,
        { routing: go.Link.Orthogonal, corner: 5 },
        $(go.Shape, { strokeWidth: 3, stroke: "#555" })); // the link shape

    let model = $(go.TreeModel);
    let key = 1, nodes = [];
    let findNodeKey = (node) => {
      for(let n of nodes) {
        if(n === node) {
          return n.key;
        }
      }
    }
    if(this.props.nodes) {
      let nodeDataArray = [];
      for(let nodePair of this.props.nodes) {
        let node = nodePair[0], parent = nodePair[1], parentKey;
        node.key = key;
        nodes.push(node);
        if(parent) {
          parentKey = findNodeKey(parent);
          nodeDataArray.push({
            key: key,
            name: node.type,
            parent: parentKey
          })
        }else {
          nodeDataArray.push({
            key: key,
            name: node.type
          })
        }
        key++;
      }
      console.log(nodeDataArray);
      model.nodeDataArray = nodeDataArray;
    }
    myDiagram.model = model;

  }

  componentDidMount() {
    this.makeDiagram();
  }

  render() {
    let surfaceWidth = this.props.surfaceWidth;
    let surfaceHeight = this.props.surfaceHeight;
    let imageStyle = this.getImageStyle();
    let textStyle = this.getTextStyle();
    let styles = {
      width: "600px",
      height: "800px",
      backgroundColor: "#DAE4E4"
    }
    return (

This is a simple canvas

 this.canvas = c}>

    )
  }

  getImageHeight() {
    return Math.round(this.props.surfaceHeight / 2);
  }

  getImageStyle() {
    return {
      top: 0,
      left: 0,
      width: window.innerWidth,
      height: this.getImageHeight()
    };
  }

  getTextStyle() {
    return {
      top: this.getImageHeight() + 10,
      left: 0,
      width: this.props.surfaceWidth,
      height: 20,
      lineHeight: 20,
      fontSize: 12
    };
  }
}

const SimpleCanvasCallback = (width, height) => {
  return <ReactCanvasSimple surfaceWidth={width} surfaceHeight={height} />
}

export default SimpleCanvasCallback;
<commit_msg>update model<commit_after>import React, { Component, PropTypes } from 'react';

export class ReactCanvasSimple extends Component {

  constructor(props) {
    super(props);
    this.state = {

    }
  }

  static propTypes = {
    surfaceWidth: PropTypes.number,
    surfaceHeight: PropTypes.number,
    nodes: PropTypes.array
  };

  makeDiagram() {
    let $ = go.GraphObject.make;

    let myDiagram =
      $(go.Diagram, "myDiagramDiv",
        {
          initialContentAlignment: go.Spot.Center, // center Diagram contents
          "undoManager.isEnabled": true, // enable Ctrl-Z to undo and Ctrl-Y to redo
          layout: $(go.TreeLayout, // specify a Diagram.layout that arranges trees
                    { angle: 90, layerSpacing: 35 })
        });

    // the template we defined earlier
    myDiagram.nodeTemplate =
      $(go.Node, "Horizontal",
        { background: "#44CCFF" },
        $(go.TextBlock, "Default Text",
          { margin: 12, stroke: "white", font: "bold 16px sans-serif" },
          new go.Binding("text", "name"))
      );

    // define a Link template that routes orthogonally, with no arrowhead
    myDiagram.linkTemplate =
      $(go.Link,
        { routing: go.Link.Orthogonal, corner: 5 },
        $(go.Shape, { strokeWidth: 3, stroke: "#555" })); // the link shape

    let model = $(go.TreeModel);
    let key = 1, nodes = [];
    let findNodeKey = (node) => {
      for(let n of nodes) {
        if(n === node) {
          return n.key;
        }
      }
    }
    if(this.props.nodes) {
      let nodeDataArray = [];
      for(let nodePair of this.props.nodes) {
        let node = nodePair[0], parent = nodePair[1], parentKey;
        node.key = key;
        nodes.push(node);
        if(parent) {
          parentKey = findNodeKey(parent);
          nodeDataArray.push({
            key: key,
            name: node.type,
            parent: parentKey
          })
        }else {
          nodeDataArray.push({
            key: key,
            name: node.type
          })
        }
        key++;
      }
      // console.log(nodeDataArray);
      model.nodeDataArray = nodeDataArray;
    }
    myDiagram.model = model;
  }

  updateModel(myDiagram) {
    let model = $(go.TreeModel);
    let key = 1, nodes = [];
    let findNodeKey = (node) => {
      for(let n of nodes) {
        if(n === node) {
          return n.key;
        }
      }
    }
    if(this.props.nodes) {
      let nodeDataArray = [];
      for(let nodePair of this.props.nodes) {
        let node = nodePair[0], parent = nodePair[1], parentKey;
        node.key = key;
        nodes.push(node);
        if(parent) {
          parentKey = findNodeKey(parent);
          nodeDataArray.push({
            key: key,
            name: node.type,
            parent: parentKey
          })
        }else {
          nodeDataArray.push({
            key: key,
            name: node.type
          })
        }
        key++;
      }
      // console.log(nodeDataArray);
      model.nodeDataArray = nodeDataArray;
    }
    myDiagram.model = model;
  }

  componentDidMount() {
    this.makeDiagram();
  }

  componentWillUpdate() {

  }

  render() {
    let surfaceWidth = this.props.surfaceWidth;
    let surfaceHeight = this.props.surfaceHeight;
    let imageStyle = this.getImageStyle();
    let textStyle = this.getTextStyle();
    let styles = {
      width: "600px",
      height: "800px",
      backgroundColor: "#DAE4E4"
    }
    return (

Node tree displayed using gojs

 this.canvas = c}>

    )
  }

  getImageHeight() {
    return Math.round(this.props.surfaceHeight / 2);
  }

  getImageStyle() {
    return {
      top: 0,
      left: 0,
      width: window.innerWidth,
      height: this.getImageHeight()
    };
  }

  getTextStyle() {
    return {
      top: this.getImageHeight() + 10,
      left: 0,
      width: this.props.surfaceWidth,
      height: 20,
      lineHeight: 20,
      fontSize: 12
    };
  }
}

const SimpleCanvasCallback = (width, height) => {
  return <ReactCanvasSimple surfaceWidth={width} surfaceHeight={height} />
}

export default SimpleCanvasCallback;
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import {
  View,
  FlatList,
  StatusBar,
  Text,
  Image,
  ScrollView,
} from 'react-native';

import { Icon, Button, Rating, Divider, Avatar } from 'react-native-elements';

import Page from '../../components/Page';
import RefreshFlatList, { RefreshState } from '../../components/RefreshFlatList';
import Toast from '../../components/Toast';

import { theme } from '../../theme';
import styles from './index.style';

import { item } from '../../services/book';

/**
 *
 * @param {*} number
 * @param {*} fixed
 * @param {*} type 0: round 1: floor 2: ceil
 */
function fixedRound(number, fixed, type = 0) {
  if (!fixed) {
    fixed = 0;
  }
  // 输入必须为数字
  if (typeof number !== 'number' || typeof fixed !== 'number')
    throw new Error('Parameters should be type of number!');
  // fixed 必须为整数
  if (fixed % 1 !== 0)
    throw new Error('Parameter `fixed` should be an integer!');

  if (fixed === 0) return Math.round(number);
  var t = Math.pow(10, fixed);
  switch (type) {
    case 0: return Math.round(number * t) / t;
    case 1: return Math.floor(number * t) / t;
    case 2: return Math.ceil(number * t) / t;
    default:
      throw new Error(`No type ${type}`);
  }

}

const formatNumber = (number, fixed = 0, unit = true, type = 0) => {
  if (number >= 10000) {
    return `${fixedRound(number / 10000, fixed, type)}${unit ? '万' : ''}`;
  }
  return number;
}

const subword = (str) => {
  if (str.length > 100) {
    return `${str.substring(0, 100)}...`;
  }
  return str;
}

class BookScreen extends Component {
  static navigationOptions = ({ navigation, screenProps }) => {
    return {
      headerStyle: {
        backgroundColor: theme.styles.variables.colors.transparent,
      },
      headerRight: (
        <View style={theme.styles.navRightContainer}>
          <Icon
            containerStyle={theme.styles.navButtonContainer}
            name='share-alternative'
            type='entypo'
            color={theme.styles.navButton.color}
            underlayColor={theme.styles.navButton.underlayColor}
            onPress={() => { }}
          />
        </View>
      ),
      tabBarVisible: false,
    };
  };
  constructor(props) {
    super(props);

    this.state = {
      book: {},
    }

    this.onFetch = this.onFetch.bind(this);
    this.renderListStyleItem = this.renderListStyleItem.bind(this);
    this.renderBookInfo = this.renderBookInfo.bind(this);
    this.renderBookStatistics = this.renderBookStatistics.bind(this);
    this.renderBookStatisticsItem = this.renderBookStatisticsItem.bind(this);
    this.renderBookDetail = this.renderBookDetail.bind(this);
    this.renderBookHonor = this.renderBookHonor.bind(this);
    this.renderComment = this.renderComment.bind(this);
    this.renderCommmentList = this.renderCommmentList.bind(this);
    this.renderBookComment = this.renderBookComment.bind(this);
    this.renderAuthorBooks = this.renderAuthorBooks.bind(this);
    this.renderAuthorInfo = this.renderAuthorInfo.bind(this);
  }

  componentDidMount() {
    this.onFetch();
  }

  async onFetch() {
    const { err, data } = await item(this.props.navigation.state.params.bookId);
    if (err) {
      return;
    }
    if (!data) {
      return;
    }

    this.setState({
      book: data,
    });
  }

  renderListStyleItem(item) {
    return (
      <View style={styles.listStyleItem.container}>
        <Text style={styles.listStyleItem.label}>{item.label ? item.label : ''}</Text>
        <Text style={styles.listStyleItem.value}>{item.value ? item.value : ''}</Text>
        <Icon
          containerStyle={styles.listStyleItem.chevron.container}
          name='chevron-right'
          type='entypo'
          size={styles.listStyleItem.chevron.size}
          color={styles.listStyleItem.chevron.color}
          underlayColor={styles.listStyleItem.chevron.color}
        />
      </View>
    )
  }

  renderBookInfo(book) {
    return (
      <View style={styles.info.container}>
        <Image source={{ uri: `https://qidian.qpic.cn/qdbimg/349573/${book.BookId}/180` }} style={styles.info.preview} />
        <View style={styles.info.text.container}>
          <Text style={styles.info.text.title}>{book.BookName ? book.BookName : '--'}</Text>
          <Text style={styles.info.text.author}>{book.Author ? book.Author : '--'}</Text>
          <View style={[styles.info.text.inline]}>
            <Rating style={styles.info.text.rating} ratingCount={5} startingValue={+book.BookStar} readonly={true} imageSize={theme.styles.variables.size.md} />
            <Text style={styles.info.text.others}>{book.BssReadTotal ? `${formatNumber(book.BssReadTotal)}人读过` : ''}</Text>
          </View>
          <Text style={styles.info.text.others}>{book.CategoryName && book.SubCategoryName ? `${book.CategoryName} | ${book.SubCategoryName}` : '--'}</Text>
          <Text style={styles.info.text.others}>{book.WordsCnt && book.BookStatus ? `${formatNumber(book.WordsCnt, 1)}字 | ${book.BookStatus}` : '--'}</Text>
        </View>
      </View>
    )
  }

  renderBookStatisticsItem(item) {
    return (
      <View key={item.label} style={styles.statistics.item.container}>
        <View style={styles.statistics.item.data.container}>
          <Text style={styles.statistics.item.data.number}>{item.number ? item.number : '--'}</Text>
          <Text style={styles.statistics.item.data.unit}>{item.unit ? item.unit : ''}</Text>
        </View>
        <Text style={styles.statistics.item.label}>{item.label}</Text>
      </View>
    )
  }

  renderBookStatistics(book) {
    const statistics = [{
      label: '月票',
      number: book.MonthTicketCount,
    }, {
      label: '推荐',
      number: formatNumber(book.RecommendAll, 0, false),
      unit: '万'
    }, {
      label: '打赏',
      number: formatNumber(book.DonateCount, 1, false),
      unit: '万次',
    }, {
      label: '粉丝',
      number: formatNumber(book.BookFansCount, 1, false, 1),
      unit: '万+',
    }];
    return (
      <View style={styles.statistics.container}>
        {statistics.map(item => this.renderBookStatisticsItem(item))}
      </View>
    )
  }

  renderBookDetail(book) {
    return (
      <View style={styles.detail.container}>
        <View style={styles.detail.description.container}>
          <Text style={styles.detail.description.title}>简介</Text>
          <Text style={styles.detail.description.text}>{book.Description ? book.Description : '--'}</Text>
        </View>
        {this.renderListStyleItem({ label: '目录', value: `连载至 ${book.TotalChapterCount} 章` })}
      </View>
    );
  }

  renderBookHonor(book) {
    return (
      <View style={styles.honor.container}>
        {this.renderListStyleItem({ label: '作品荣誉', value: `${book.BookHonor && book.BookHonor.length ? book.BookHonor[0].Honors : ''}` })}
      </View>
    );
  }

  renderComment(item) {
    return (
      <View key={item.Id} style={styles.comment.item.container}>
        <Image style={styles.comment.item.avatar} source={{ uri: `https://qidian.qpic.cn/qd_face/349573/${item.UserId}/100` }} />
        <View style={styles.comment.item.textContainer}>
          <View style={styles.comment.item.name.container}>
            <Text>{item.UserName}</Text>
          </View>
          <Text style={styles.comment.item.info}>{`${item.PostDate}：${item.From}`}</Text>
          <Text style={styles.comment.item.text}>{subword(item.Body)}</Text>
        </View>
      </View>
    );
  }

  renderCommmentList(list) {
    if (!list || !list.length) {
      return false;
    }
    return (
      <View style={styles.area.contentContainer}>
        {list.map(item => this.renderComment(item))}
      </View>
    )
  }

  renderBookComment(book) {
    return (
      <View style={styles.area.container}>
        {this.renderListStyleItem({ label: '书评', value: `${book.BookForumCount ? `${formatNumber(book.BookForumCount, 0, true, 1)}+` : ''}` })}
        {this.renderCommmentList(book.BookReviewList)}
      </View>
    );
  }

  renderAuthorBooks(books) {
    return (
      <ScrollView horizontal={true} style={styles.author.books.container}>
        {
          books.map(book => {
            return (
              <View key={book.BookId} style={styles.author.books.book.container}>
                <Image style={styles.author.books.book.preview} source={{ uri: `https://qidian.qpic.cn/qdbimg/349573/${book.BookId}/180` }} />
                <View style={styles.author.books.book.titleWrapper}>
                  <Text style={styles.author.books.book.title}>{book.BookName}</Text>
                </View>
                <Text style={styles.author.books.book.readers}>{`${formatNumber(book.BssReadTotal, 1, true, 1)}人...`}</Text>
              </View>
            )
          })
        }
      </ScrollView>
    )
  }

  renderAuthorInfo(book) {
    const { AuthorInfo: author = {}, AuthorRecommend: authorBooks = [] } = book;
    return (
      <View style={styles.area.container}>
        {this.renderListStyleItem({ label: '作家', value: '' })}
        <View style={styles.area.contentContainer}>
          <View style={styles.author.info.container}>
            <Avatar
              medium
              rounded
              source={{ uri: author.RealImageUrl }}
            />
            <View style={styles.author.info.textContainer}>
              <Text style={styles.author.info.name}>{author.AuthorName}</Text>
              <Text style={styles.author.info.info}>{author.AuthorDesc}</Text>
            </View>
          </View>
          {this.renderAuthorBooks(authorBooks)}
        </View>
      </View>
    );
  }

  render() {
    const book = this.state.book;
    return (
      <Page containerStyle={styles.page}>
        <ScrollView style={{ flex: 1, marginBottom: 20, }}>
          {this.renderBookInfo(book)}
          {this.renderBookStatistics(book)}
          {this.renderBookDetail(book)}
          {this.renderBookHonor(book)}
          {this.renderBookComment(book)}
          {this.renderAuthorInfo(book)}
        </ScrollView>
      </Page>
    );
  }
}

export default BookScreen;
<commit_msg>Show or hide book title while scrolling<commit_after>import React, { Component } from 'react';
import {
  View,
  FlatList,
  StatusBar,
  Text,
  Image,
  ScrollView,
} from 'react-native';

import { Icon, Button, Rating, Divider, Avatar } from 'react-native-elements';

import Page from '../../components/Page';
import RefreshFlatList, { RefreshState } from '../../components/RefreshFlatList';
import Toast from '../../components/Toast';

import { theme } from '../../theme';
import styles from './index.style';

import { item } from '../../services/book';

/**
 *
 * @param {*} number
 * @param {*} fixed
 * @param {*} type 0: round 1: floor 2: ceil
 */
function fixedRound(number, fixed, type = 0) {
  if (!fixed) {
    fixed = 0;
  }
  // 输入必须为数字
  if (typeof number !== 'number' || typeof fixed !== 'number')
    throw new Error('Parameters should be type of number!');
  // fixed 必须为整数
  if (fixed % 1 !== 0)
    throw new Error('Parameter `fixed` should be an integer!');

  if (fixed === 0) return Math.round(number);
  var t = Math.pow(10, fixed);
  switch (type) {
    case 0: return Math.round(number * t) / t;
    case 1: return Math.floor(number * t) / t;
    case 2: return Math.ceil(number * t) / t;
    default:
      throw new Error(`No type ${type}`);
  }

}

const formatNumber = (number, fixed = 0, unit = true, type = 0) => {
  if (number >= 10000) {
    return `${fixedRound(number / 10000, fixed, type)}${unit ? '万' : ''}`;
  }
  return number;
}

const subword = (str) => {
  if (str.length > 100) {
    return `${str.substring(0, 100)}...`;
  }
  return str;
}

class BookScreen extends Component {
  static navigationOptions = ({ navigation, screenProps }) => {
    return {
      title: `${navigation.state.params.title ? navigation.state.params.title : ''}`,
      headerStyle: {
        backgroundColor: theme.styles.variables.colors.transparent,
      },
      headerRight: (
        <View style={theme.styles.navRightContainer}>
          <Icon
            containerStyle={theme.styles.navButtonContainer}
            name='share-alternative'
            type='entypo'
            color={theme.styles.navButton.color}
            underlayColor={theme.styles.navButton.underlayColor}
            onPress={() => { }}
          />
        </View>
      ),
      tabBarVisible: false,
    };
  };
  constructor(props) {
    super(props);

    this.state = {
      book: {},
    }

    this.onFetch = this.onFetch.bind(this);
    this.onScrollOverTitle = this.onScrollOverTitle.bind(this);
    this.renderListStyleItem = this.renderListStyleItem.bind(this);
    this.renderBookInfo = this.renderBookInfo.bind(this);
    this.renderBookStatistics = this.renderBookStatistics.bind(this);
    this.renderBookStatisticsItem = this.renderBookStatisticsItem.bind(this);
    this.renderBookDetail = this.renderBookDetail.bind(this);
    this.renderBookHonor = this.renderBookHonor.bind(this);
    this.renderComment = this.renderComment.bind(this);
    this.renderCommmentList = this.renderCommmentList.bind(this);
    this.renderBookComment = this.renderBookComment.bind(this);
    this.renderAuthorBooks = this.renderAuthorBooks.bind(this);
    this.renderAuthorInfo = this.renderAuthorInfo.bind(this);
  }

  componentDidMount() {
    this.onFetch();
  }

  async onFetch() {
    const { err, data } = await item(this.props.navigation.state.params.bookId);
    if (err) {
      return;
    }
    if (!data) {
      return;
    }

    this.setState({
      book: data,
    });
  }

  onScrollOverTitle(y) {
    if (!this.overed && y >= 35) {
      this.overed = true;
      this.props.navigation.setParams({
        title: this.state.book.BookName,
      });
    } else if (this.overed && y < 35) {
      this.overed = false;
      this.props.navigation.setParams({
        title: '',
      });
    }
  }

  renderListStyleItem(item) {
    return (
      <View style={styles.listStyleItem.container}>
        <Text style={styles.listStyleItem.label}>{item.label ? item.label : ''}</Text>
        <Text style={styles.listStyleItem.value}>{item.value ? item.value : ''}</Text>
        <Icon
          containerStyle={styles.listStyleItem.chevron.container}
          name='chevron-right'
          type='entypo'
          size={styles.listStyleItem.chevron.size}
          color={styles.listStyleItem.chevron.color}
          underlayColor={styles.listStyleItem.chevron.color}
        />
      </View>
    )
  }

  renderBookInfo(book) {
    return (
      <View style={styles.info.container}>
        <Image source={{ uri: `https://qidian.qpic.cn/qdbimg/349573/${book.BookId}/180` }} style={styles.info.preview} />
        <View style={styles.info.text.container}>
          <Text style={styles.info.text.title}>{book.BookName ? book.BookName : '--'}</Text>
          <Text style={styles.info.text.author}>{book.Author ? book.Author : '--'}</Text>
          <View style={[styles.info.text.inline]}>
            <Rating style={styles.info.text.rating} ratingCount={5} startingValue={+book.BookStar} readonly={true} imageSize={theme.styles.variables.size.md} />
            <Text style={styles.info.text.others}>{book.BssReadTotal ? `${formatNumber(book.BssReadTotal)}人读过` : ''}</Text>
          </View>
          <Text style={styles.info.text.others}>{book.CategoryName && book.SubCategoryName ? `${book.CategoryName} | ${book.SubCategoryName}` : '--'}</Text>
          <Text style={styles.info.text.others}>{book.WordsCnt && book.BookStatus ? `${formatNumber(book.WordsCnt, 1)}字 | ${book.BookStatus}` : '--'}</Text>
        </View>
      </View>
    )
  }

  renderBookStatisticsItem(item) {
    return (
      <View key={item.label} style={styles.statistics.item.container}>
        <View style={styles.statistics.item.data.container}>
          <Text style={styles.statistics.item.data.number}>{item.number ? item.number : '--'}</Text>
          <Text style={styles.statistics.item.data.unit}>{item.unit ? item.unit : ''}</Text>
        </View>
        <Text style={styles.statistics.item.label}>{item.label}</Text>
      </View>
    )
  }

  renderBookStatistics(book) {
    const statistics = [{
      label: '月票',
      number: book.MonthTicketCount,
    }, {
      label: '推荐',
      number: formatNumber(book.RecommendAll, 0, false),
      unit: '万'
    }, {
      label: '打赏',
      number: formatNumber(book.DonateCount, 1, false),
      unit: '万次',
    }, {
      label: '粉丝',
      number: formatNumber(book.BookFansCount, 1, false, 1),
      unit: '万+',
    }];
    return (
      <View style={styles.statistics.container}>
        {statistics.map(item => this.renderBookStatisticsItem(item))}
      </View>
    )
  }

  renderBookDetail(book) {
    return (
      <View style={styles.detail.container}>
        <View style={styles.detail.description.container}>
          <Text style={styles.detail.description.title}>简介</Text>
          <Text style={styles.detail.description.text}>{book.Description ? book.Description : '--'}</Text>
        </View>
        {this.renderListStyleItem({ label: '目录', value: `连载至 ${book.TotalChapterCount} 章` })}
      </View>
    );
  }

  renderBookHonor(book) {
    return (
      <View style={styles.honor.container}>
        {this.renderListStyleItem({ label: '作品荣誉', value: `${book.BookHonor && book.BookHonor.length ? book.BookHonor[0].Honors : ''}` })}
      </View>
    );
  }

  renderComment(item) {
    return (
      <View key={item.Id} style={styles.comment.item.container}>
        <Image style={styles.comment.item.avatar} source={{ uri: `https://qidian.qpic.cn/qd_face/349573/${item.UserId}/100` }} />
        <View style={styles.comment.item.textContainer}>
          <View style={styles.comment.item.name.container}>
            <Text>{item.UserName}</Text>
          </View>
          <Text style={styles.comment.item.info}>{`${item.PostDate}：${item.From}`}</Text>
          <Text style={styles.comment.item.text}>{subword(item.Body)}</Text>
        </View>
      </View>
    );
  }

  renderCommmentList(list) {
    if (!list || !list.length) {
      return false;
    }
    return (
      <View style={styles.area.contentContainer}>
        {list.map(item => this.renderComment(item))}
      </View>
    )
  }

  renderBookComment(book) {
    return (
      <View style={styles.area.container}>
        {this.renderListStyleItem({ label: '书评', value: `${book.BookForumCount ? `${formatNumber(book.BookForumCount, 0, true, 1)}+` : ''}` })}
        {this.renderCommmentList(book.BookReviewList)}
      </View>
    );
  }

  renderAuthorBooks(books) {
    return (
      <ScrollView horizontal={true} style={styles.author.books.container}>
        {
          books.map(book => {
            return (
              <View key={book.BookId} style={styles.author.books.book.container}>
                <Image style={styles.author.books.book.preview} source={{ uri: `https://qidian.qpic.cn/qdbimg/349573/${book.BookId}/180` }} />
                <View style={styles.author.books.book.titleWrapper}>
                  <Text style={styles.author.books.book.title}>{book.BookName}</Text>
                </View>
                <Text style={styles.author.books.book.readers}>{`${formatNumber(book.BssReadTotal, 1, true, 1)}人...`}</Text>
              </View>
            )
          })
        }
      </ScrollView>
    )
  }

  renderAuthorInfo(book) {
    const { AuthorInfo: author = {}, AuthorRecommend: authorBooks = [] } = book;
    return (
      <View style={styles.area.container}>
        {this.renderListStyleItem({ label: '作家', value: '' })}
        <View style={styles.area.contentContainer}>
          <View style={styles.author.info.container}>
            <Avatar
              medium
              rounded
              source={{ uri: author.RealImageUrl }}
            />
            <View style={styles.author.info.textContainer}>
              <Text style={styles.author.info.name}>{author.AuthorName}</Text>
              <Text style={styles.author.info.info}>{author.AuthorDesc}</Text>
            </View>
          </View>
          {this.renderAuthorBooks(authorBooks)}
        </View>
      </View>
    );
  }

  render() {
    const book = this.state.book;
    return (
      <Page containerStyle={styles.page}>
        <ScrollView
          style={{ flex: 1, marginBottom: 20, }}
          onScroll={(e) => {
            this.onScrollOverTitle(e.nativeEvent.contentOffset.y);
          }}
          scrollEventThrottle={3}
        >
          {this.renderBookInfo(book)}
          {this.renderBookStatistics(book)}
          {this.renderBookDetail(book)}
          {this.renderBookHonor(book)}
          {this.renderBookComment(book)}
          {this.renderAuthorInfo(book)}
        </ScrollView>
      </Page>
    );
  }
}

export default BookScreen;
<|endoftext|>


<commit_before>/*jslint indent: 2, unparam: true*/
/*global $: false, document: false, togglbutton: false, createTag: false*/
'use strict';

togglbutton.render('#tickets-show:not(.toggl)', {observe: true}, function (elem) {

  var link,
    container = createTag('li', 'toggle-container'),
    descFunc,
    projectFunc;

  descFunc = function () {
    return document.querySelector('#copyButton1').getAttribute('data-clipboard-text');
  };

  projectFunc = function () {
    return $('h1.header-w > span').textContent || "";
  };

  link = togglbutton.createTimerLink({
    className: 'assembla',
    description: descFunc,
    projectName: projectFunc,
  });

  container.appendChild(link);
  $('ul.menu-submenu').appendChild(container);
});
<commit_msg>Fixed Assembla selector, closes #470<commit_after>/*jslint indent: 2, unparam: true*/
/*global $: false, document: false, togglbutton: false, createTag: false*/
'use strict';

togglbutton.render('#ticketDetailsContainer:not(.toggl)', {observe: true}, function (elem) {

  var link,
    container = createTag('li', 'toggle-container'),
    descFunc,
    projectFunc;

  descFunc = function () {
    return document.querySelector('#copyButton1').getAttribute('data-clipboard-text');
  };

  projectFunc = function () {
    return $('h1.header-w > span').textContent || "";
  };

  link = togglbutton.createTimerLink({
    className: 'assembla',
    description: descFunc,
    projectName: projectFunc,
  });

  container.appendChild(link);
  $('ul.menu-submenu').appendChild(container);
});
<|endoftext|>