<commit_before>import React from 'react'
import {capitalize, pluralize} from 'humanize-plus'
import Immutable from 'immutable'

import AreaOfStudy from '../elements/areaOfStudy'
import StudentSummary from '../elements/studentSummary'

import checkStudentGraduatability from '../helpers/checkStudentGraduatability'

class GraduationStatus extends React.Component {
	constructor(props) {
		super(props)
		this.state = {
			graduatability: null,
			areaDetails: Immutable.List(),
		}
	}

	componentWillReceiveProps(nextProps) {
		let graduatabilityPromise = checkStudentGraduatability(nextProps.student)

		graduatabilityPromise.then((graduationStatus) => {
			let {graduatability, areaDetails} = graduationStatus
			this.setState({graduatability, areaDetails})
		})
	}

	componentWillMount() {
		this.componentWillReceiveProps(this.props)
	}

	render() {
		// console.info('graduation-status render', this.props.student)
		let student = this.props.student

		if (!student) {
			return null
		}

		let summary = <StudentSummary
			student={student}
			graduatability={this.state.graduatability} />

		let sections = student.areasByType
			.map((areas, areaType) => {
				let pluralType = pluralize(2, areaType, areaType === 'emphasis' ? 'emphases' : undefined)

				let areaTypeHeading =

{capitalize(pluralType)}

				let areaElements = areas.toList().map((area, index) => {
					let areaResult = this.state.areaDetails.find(a => a.id === area.id)

					let props = {
						key: `${area.id}-${index}`,
						student,
						areaResult,
						area,
					}
					return <AreaOfStudy {...props} />
				}).toJS()

				areaElements.push(
					<button key='add-button' className='add-area-of-study'>
						{`Add ${capitalize(areaType)}`}
					</button>)

				return

					{areaTypeHeading}
					{areaElements}

			}).toJS()

		return

			{summary}
			{sections}

	}
}

GraduationStatus.propTypes = {
	student: React.PropTypes.object.isRequired,
}

GraduationStatus.defaultProps = {
	sections: []
}

export default GraduationStatus
<commit_msg>Force Immutable to generate an array, instead of a map, in GradStatus<commit_after>import React from 'react'
import {capitalize, pluralize} from 'humanize-plus'
import Immutable from 'immutable'

import AreaOfStudy from '../elements/areaOfStudy'
import StudentSummary from '../elements/studentSummary'

import checkStudentGraduatability from '../helpers/checkStudentGraduatability'

class GraduationStatus extends React.Component {
	constructor(props) {
		super(props)
		this.state = {
			graduatability: null,
			areaDetails: Immutable.List(),
		}
	}

	componentWillReceiveProps(nextProps) {
		let graduatabilityPromise = checkStudentGraduatability(nextProps.student)

		graduatabilityPromise.then((graduationStatus) => {
			let {graduatability, areaDetails} = graduationStatus
			this.setState({graduatability, areaDetails})
		})
	}

	componentWillMount() {
		this.componentWillReceiveProps(this.props)
	}

	render() {
		// console.info('graduation-status render', this.props.student)
		let student = this.props.student

		if (!student) {
			return null
		}

		let summary = <StudentSummary
			student={student}
			graduatability={this.state.graduatability} />

		let sections = student.areasByType
			.map((areas, areaType) => {
				let pluralType = pluralize(2, areaType, areaType === 'emphasis' ? 'emphases' : undefined)

				let areaTypeHeading =

{capitalize(pluralType)}

				let areaElements = areas.toList().map((area, index) => {
					let areaResult = this.state.areaDetails.find(a => a.id === area.id)

					let props = {
						key: `${area.id}-${index}`,
						student,
						areaResult,
						area,
					}
					return <AreaOfStudy {...props} />
				}).toJS()

				areaElements.push(
					<button key='add-button' className='add-area-of-study'>
						{`Add ${capitalize(areaType)}`}
					</button>)

				return

					{areaTypeHeading}
					{areaElements}

			}).toArray()

		return

			{summary}
			{sections}

	}
}

GraduationStatus.propTypes = {
	student: React.PropTypes.object.isRequired,
}

GraduationStatus.defaultProps = {
	sections: []
}

export default GraduationStatus
<|endoftext|>


<commit_before>'use strict';

/* global jsondiffpatch */

angular.module('arethusa.review').service('review', [
  'configurator',
  'state',
  '$rootScope',
  'navigator',
  'plugins',
  function (configurator, state, $rootScope, navigator, plugins) {
    var self = this;
    this.name = "review";

    var retriever;
    var doc;

    this.externalDependencies = [
      "bower_components/jsondiffpatch/build/bundle.min.js"
    ];

    self.goldTokens = {};

    self.defaultConf = {
      link : true,
      contextMenu : true,
      contextMenuTemplate : "templates/arethusa.review/context_menu.html"
    };

    function DiffCounts() {
      this.tokens = 0;
      this.attrs  = 0;
    }

    var lazyMorph;
    function morph() {
      if (!lazyMorph) lazyMorph = plugins.get('morph');
      return lazyMorph;
    }

    function configure() {
      configurator.getConfAndDelegate(self, ['hideMode']);
      configurator.getStickyConf(self, ['link', 'autoDiff']);
      self.comparators = [
        'morphology.lemma',
        'morphology.postag',
        'head.id',
        'relation.label'
      ];
      if (self.hideMode) {
        self.contextMenu = false;
        self.autoDiff = false;
        self.link = true;
      }
      var retrievers = configurator.getRetrievers(self.conf.retrievers);
      retriever = retrievers.TreebankRetriever;
      self.diffActive = false;
    }

    function addStyleInfo(tokens) {
      angular.forEach(tokens, function (token, id) {
        var form = token.morphology;
        if (form) {
          morph().postagToAttributes(form);
          token.style = morph().styleOf(form);
        }
      });
    }

    function broadcast() {
      self.diffActive = true;
      $rootScope.$broadcast('diffLoaded');
    }

    self.goToCurrentChunk = function() {
      self.pos = navigator.status.currentPos;
      self.goldTokens = doc[self.pos].tokens;
      addStyleInfo(self.goldTokens);
    };

    function loadDocument() {
      retriever.getData(function (res) {
        doc = res;
        postInit(true);
      });
    }

    function extract(obj) {
      return arethusaUtil.inject({}, obj, function(memo, id, token) {
        memo[id] = arethusaUtil.copySelection(token, self.comparators);
      });
    }

    function countDiffs() {
      var dC = self.diffCounts = new DiffCounts();
      angular.forEach(self.diff, function(d) {
        dC.tokens++;
        angular.forEach(d, function(attr) { dC.attrs++; });
      });
    }

    this.compare = function () {
      self.diff = jsondiffpatch.diff(
        extract(state.tokens),
        extract(self.goldTokens)
      );

      countDiffs();

      angular.forEach(self.diff, function (diff, id) {
        state.setState(id, 'diff', diff);
      });
      broadcast();
    };

    function postInit(initialLoad) {
      if (self.link || initialLoad) self.goToCurrentChunk();

      plugins.doAfter('depTree', function() {
        if (self.autoDiff) self.compare();
      });
    }

    this.init = function () {
      configure();

      if (!doc) {
        loadDocument();
      } else {
        postInit();
      }
    };
  }
]);
<commit_msg>Fix get in review<commit_after>'use strict';

/* global jsondiffpatch */

angular.module('arethusa.review').service('review', [
  'configurator',
  'state',
  '$rootScope',
  'navigator',
  'plugins',
  function (configurator, state, $rootScope, navigator, plugins) {
    var self = this;
    this.name = "review";

    var retriever;
    var doc;

    this.externalDependencies = [
      "bower_components/jsondiffpatch/build/bundle.min.js"
    ];

    self.goldTokens = {};

    self.defaultConf = {
      link : true,
      contextMenu : true,
      contextMenuTemplate : "templates/arethusa.review/context_menu.html"
    };

    function DiffCounts() {
      this.tokens = 0;
      this.attrs  = 0;
    }

    var lazyMorph;
    function morph() {
      if (!lazyMorph) lazyMorph = plugins.get('morph');
      return lazyMorph;
    }

    function configure() {
      configurator.getConfAndDelegate(self, ['hideMode']);
      configurator.getStickyConf(self, ['link', 'autoDiff']);
      self.comparators = [
        'morphology.lemma',
        'morphology.postag',
        'head.id',
        'relation.label'
      ];
      if (self.hideMode) {
        self.contextMenu = false;
        self.autoDiff = false;
        self.link = true;
      }
      var retrievers = configurator.getRetrievers(self.conf.retrievers);
      retriever = retrievers.TreebankRetriever;
      self.diffActive = false;
    }

    function addStyleInfo(tokens) {
      angular.forEach(tokens, function (token, id) {
        var form = token.morphology;
        if (form) {
          morph().postagToAttributes(form);
          token.style = morph().styleOf(form);
        }
      });
    }

    function broadcast() {
      self.diffActive = true;
      $rootScope.$broadcast('diffLoaded');
    }

    self.goToCurrentChunk = function() {
      self.pos = navigator.status.currentPos;
      self.goldTokens = doc[self.pos].tokens;
      addStyleInfo(self.goldTokens);
    };

    function loadDocument() {
      retriever.get(function (res) {
        doc = res;
        postInit(true);
      });
    }

    function extract(obj) {
      return arethusaUtil.inject({}, obj, function(memo, id, token) {
        memo[id] = arethusaUtil.copySelection(token, self.comparators);
      });
    }

    function countDiffs() {
      var dC = self.diffCounts = new DiffCounts();
      angular.forEach(self.diff, function(d) {
        dC.tokens++;
        angular.forEach(d, function(attr) { dC.attrs++; });
      });
    }

    this.compare = function () {
      self.diff = jsondiffpatch.diff(
        extract(state.tokens),
        extract(self.goldTokens)
      );

      countDiffs();

      angular.forEach(self.diff, function (diff, id) {
        state.setState(id, 'diff', diff);
      });
      broadcast();
    };

    function postInit(initialLoad) {
      if (self.link || initialLoad) self.goToCurrentChunk();

      plugins.doAfter('depTree', function() {
        if (self.autoDiff) self.compare();
      });
    }

    this.init = function () {
      configure();

      if (!doc) {
        loadDocument();
      } else {
        postInit();
      }
    };
  }
]);
<|endoftext|>


<commit_before>const fs = require('fs')
const { green } = require('chalk')

const { warn } = require('./helpers/logger')
const appPaths = require('./app-paths')

module.exports = function (cfg) {
  let file
  let content
  let error = false

  file = appPaths.resolve.app(cfg.sourceFiles.indexHtmlTemplate)
  if (!fs.existsSync(file)) {
    warn('Missing /src/index.template.html file...\n')
    error = true
  }
  content = fs.readFileSync(file, 'utf-8')

  if (content.indexOf('<base href') > -1) {
    warn(`Please remove the tag below from /src/index.template.html
   This is taken care of by Quasar automatically.
  <base href="<%= htmlWebpackPlugin.options.appBase %>">
  `)
    error = true
  }

  file = appPaths.resolve.app(cfg.sourceFiles.rootComponent)
  content = fs.readFileSync(file, 'utf-8')
  if (content.indexOf('q-app') === -1) {
    console.log(`\n Quasar requires a minor change to the root component:
   ${file}

  Please add: id="q-app" (or write #q-app if using Pug)
  to the outermost HTML element of the template.

${green('Example:')}
  <template>

      ...

  </template>
`)
    error = true
  }

  if (error) {
    process.exit(1)
  }
}
<commit_msg>feat(app): Further remove Quasar v0.x validation checks<commit_after>const fs = require('fs')
const { green } = require('chalk')

const appPaths = require('./app-paths')

module.exports = function (cfg) {
  let file
  let content
  let error = false

  file = appPaths.resolve.app(cfg.sourceFiles.rootComponent)
  content = fs.readFileSync(file, 'utf-8')
  if (content.indexOf('q-app') === -1) {
    console.log(`\n Quasar requires a minor change to the root component:
   ${file}

  Please add: id="q-app" (or write #q-app if using Pug)
  to the outermost HTML element of the template.

${green('Example:')}
  <template>

      ...

  </template>
`)
    error = true
  }

  if (error) {
    process.exit(1)
  }
}
<|endoftext|>


<commit_before>/**
 * @author Serhii Maksymchuk from Ubrainians for imCode
 * 22.06.18
 */
define(
    'imcms-super-admin-page-builder',
    [
        'imcms-bem-builder', 'imcms-components-builder', 'imcms-super-admin-tabs-builder', 'imcms-i18n-texts', 'jquery'
    ],
    function (BEM, components, superAdminTabs, texts, $) {

        texts = texts.superAdmin;

        let panels$;

        function buildSuperAdminPanels() {
            return superAdminTabs.tabBuilders.map(function (tabBuilder, index) {
                const $tab = tabBuilder.buildTab(index);

                (index === 0) ? $tab.slideDown() : $tab.slideUp();

                return $tab;
            });
        }

        function buildHead() {
            return new BEM({
                block: 'imcms-head',
                elements: {
                    'logo': $('<a>', {
                        href: '/'
                    }),
                    'title': $('<div>', {
                        'class': 'imcms-title',
                        text: texts.head
                    })
                }
            }).buildBlockStructure('<div>', {
                'class': 'imcms-info-head'
            });
        }

        function buildSuperAdmin() {
            panels$ = buildSuperAdminPanels();

            return new BEM({
                block: 'imcms-pop-up-modal',
                elements: {
                    'head': buildHead(),
                    'left-side': superAdminTabs.buildWindowTabs(panels$),
                    'right-side': $('<div>', {'class': 'imcms-right-side'}).append(panels$)
                }
            }).buildBlockStructure('<div>', {
                'class': 'imcms-info-page'
            });
        }

        return {
            build: () => {
                $('body').append(buildSuperAdmin());
            }
        };
    }
);
<commit_msg>Issue DP-112: Activate the new admin manager - Add reference to old admin;<commit_after>/**
 * @author Serhii Maksymchuk from Ubrainians for imCode
 * 22.06.18
 */
define(
    'imcms-super-admin-page-builder',
    [
        'imcms-bem-builder', 'imcms-components-builder', 'imcms-super-admin-tabs-builder', 'imcms-i18n-texts', 'jquery'
    ],
    function (BEM, components, superAdminTabs, texts, $) {

        texts = texts.superAdmin;

        let panels$;

        function buildSuperAdminPanels() {
            return superAdminTabs.tabBuilders.map(function (tabBuilder, index) {
                const $tab = tabBuilder.buildTab(index);

                (index === 0) ? $tab.slideDown() : $tab.slideUp();

                return $tab;
            });
        }

        function buildHead() {
            return new BEM({
                block: 'imcms-head',
                elements: {
                    'logo': $('<a>', {
                        href: '/'
                    }),
                    'title': $('<div>', {
                        'class': 'imcms-title',
                        text: texts.head
                    }),
                    'old-admin': components.buttons.neutralButton({
                        text: texts.oldInterface + ' \u2b95',
                        click: () => window.location = '/servlet/AdminManager',
                    }),
                }
            }).buildBlockStructure('<div>', {
                'class': 'imcms-info-head'
            });
        }

        function buildSuperAdmin() {
            panels$ = buildSuperAdminPanels();

            return new BEM({
                block: 'imcms-pop-up-modal',
                elements: {
                    'head': buildHead(),
                    'left-side': superAdminTabs.buildWindowTabs(panels$),
                    'right-side': $('<div>', {'class': 'imcms-right-side'}).append(panels$)
                }
            }).buildBlockStructure('<div>', {
                'class': 'imcms-info-page'
            });
        }

        return {
            build: () => {
                $('body').append(buildSuperAdmin());
            }
        };
    }
);
<|endoftext|>


<commit_before>var React = require('react');
var Tree = require('./tree');
var Node = require('./node');

module.exports = React.createClass({
  displayName: 'UITree',

  propTypes: {
    tree: React.PropTypes.object.isRequired,
    paddingLeft: React.PropTypes.number,
    renderNode: React.PropTypes.func.isRequired,
    noDrag: React.PropTypes.bool
  },

  getDefaultProps() {
    return {
      paddingLeft: 20
    };
  },

  getInitialState() {
    return this.init(this.props);
  },

  componentWillReceiveProps(nextProps) {
    if(!this._updated) this.setState(this.init(nextProps));
    else this._updated = false;
  },

  init(props) {
    var tree = new Tree(props.tree);
    tree.isNodeCollapsed = props.isNodeCollapsed;
    tree.renderNode = props.renderNode;
    tree.changeNodeCollapsed = props.changeNodeCollapsed;
    tree.updateNodesPosition();

    return {
      tree: tree,
      dragging: {
        id: null,
        x: null,
        y: null,
        w: null,
        h: null
      }
    };
  },

  getDraggingDom() {
    var tree = this.state.tree;
    var dragging = this.state.dragging;

    if(dragging && dragging.id) {
      var draggingIndex = tree.getIndex(dragging.id);
      var draggingStyles = {
        top: dragging.y,
        left: dragging.x,
        width: dragging.w
      };

      return (

          <Node
            tree={tree}
            index={draggingIndex}
            paddingLeft={this.props.paddingLeft}
          />

      );
    }

    return null;
  },

  render() {
    var tree = this.state.tree;
    var dragging = this.state.dragging;
    var draggingDom = this.getDraggingDom();

    var dragStart = (this.props.noDrag ? null : this.dragStart);

    return (

        {draggingDom}
        <Node
          tree={tree}
          index={tree.getIndex(1)}
          key={1}
          paddingLeft={this.props.paddingLeft}
          onDragStart={dragStart}
          onCollapse={this.toggleCollapse}
          dragging={dragging && dragging.id}
        />

    );
  },

  dragStart(id, dom, e) {
    this.dragging = {
      id: id,
      w: dom.offsetWidth,
      h: dom.offsetHeight,
      x: dom.offsetLeft,
      y: dom.offsetTop
    };

    this._startX = dom.offsetLeft;
    this._startY = dom.offsetTop;
    this._offsetX = e.clientX;
    this._offsetY = e.clientY;
    this._start = true;

    window.addEventListener('mousemove', this.drag);
    window.addEventListener('mouseup', this.dragEnd);
  },

  // oh
  drag(e) {
    if(this._start) {
      this.setState({
        dragging: this.dragging
      });
      this._start = false;
    }

    var tree = this.state.tree;
    var dragging = this.state.dragging;
    var paddingLeft = this.props.paddingLeft;
    var newIndex = null;
    var index = tree.getIndex(dragging.id);
    var collapsed = index.node.collapsed;

    var _startX = this._startX;
    var _startY = this._startY;
    var _offsetX = this._offsetX;
    var _offsetY = this._offsetY;

    var pos = {
      x: _startX + e.clientX - _offsetX,
      y: _startY + e.clientY - _offsetY
    };
    dragging.x = pos.x;
    dragging.y = pos.y;

    var diffX = dragging.x - paddingLeft/2 - (index.left-2) * paddingLeft;
    var diffY = dragging.y - dragging.h/2 - (index.top-2) * dragging.h;

    if(diffX < 0) { // left
      if(index.parent && !index.next) {
        newIndex = tree.move(index.id, index.parent, 'after');
      }
    } else if(diffX > paddingLeft) { // right
      if(index.prev && !tree.getIndex(index.prev).node.collapsed) {
        newIndex = tree.move(index.id, index.prev, 'append');
      }
    }

    if(newIndex) {
      index = newIndex;
      newIndex.node.collapsed = collapsed;
      dragging.id = newIndex.id;
    }

    if(diffY < 0) { // up
      var above = tree.getNodeByTop(index.top-1);
      newIndex = tree.move(index.id, above.id, 'before');
    } else if(diffY > dragging.h) { // down
      if(index.next) {
        var below = tree.getIndex(index.next);
        if(below.children && below.children.length && !below.node.collapsed) {
          newIndex = tree.move(index.id, index.next, 'prepend');
        } else {
          newIndex = tree.move(index.id, index.next, 'after');
        }
      } else {
        var below = tree.getNodeByTop(index.top+index.height);
        if(below && below.parent !== index.id) {
          if(below.children && below.children.length) {
            newIndex = tree.move(index.id, below.id, 'prepend');
          } else {
            newIndex = tree.move(index.id, below.id, 'after');
          }
        }
      }
    }

    if(newIndex) {
      newIndex.node.collapsed = collapsed;
      dragging.id = newIndex.id;
    }

    this.setState({
      tree: tree,
      dragging: dragging
    });
  },

  dragEnd() {
    this.setState({
      dragging: {
        id: null,
        x: null,
        y: null,
        w: null,
        h: null
      }
    });

    this.change(this.state.tree);
    window.removeEventListener('mousemove', this.drag);
    window.removeEventListener('mouseup', this.dragEnd);
  },

  change(tree) {
    this._updated = true;
    if(this.props.onChange) this.props.onChange(tree.obj);
  },

  toggleCollapse(nodeId) {
    var tree = this.state.tree;
    var index = tree.getIndex(nodeId);
    var node = index.node;
    node.collapsed = !node.collapsed;
    tree.updateNodesPosition();

    this.setState({
      tree: tree
    });

    this.change(tree);
  }
});
<commit_msg>No drap/drop below leaf nodes<commit_after>var React = require('react');
var Tree = require('./tree');
var Node = require('./node');

module.exports = React.createClass({
  displayName: 'UITree',

  propTypes: {
    tree: React.PropTypes.object.isRequired,
    paddingLeft: React.PropTypes.number,
    renderNode: React.PropTypes.func.isRequired,
    noDrag: React.PropTypes.bool
  },

  getDefaultProps: function getDefaultProps() {
    return {
      paddingLeft: 20
    };
  },

  getInitialState: function getInitialState() {
    return this.init(this.props);
  },

  componentWillReceiveProps: function componentWillReceiveProps(nextProps) {
    if (!this._updated) this.setState(this.init(nextProps));else this._updated = false;
  },

  init: function init(props) {
    var tree = new Tree(props.tree);
    tree.isNodeCollapsed = props.isNodeCollapsed;
    tree.renderNode = props.renderNode;
    tree.changeNodeCollapsed = props.changeNodeCollapsed;
    tree.updateNodesPosition();

    return {
      tree: tree,
      dragging: {
        id: null,
        x: null,
        y: null,
        w: null,
        h: null
      }
    };
  },

  getDraggingDom: function getDraggingDom() {
    var tree = this.state.tree;
    var dragging = this.state.dragging;

    if (dragging && dragging.id) {
      var draggingIndex = tree.getIndex(dragging.id);
      var draggingStyles = {
        top: dragging.y,
        left: dragging.x,
        width: dragging.w
      };

      return React.createElement(
        'div',
        { className: 'm-draggable', style: draggingStyles },
        React.createElement(Node, {
          tree: tree,
          index: draggingIndex,
          paddingLeft: this.props.paddingLeft
        })
      );
    }

    return null;
  },

  render: function render() {
    var tree = this.state.tree;
    var dragging = this.state.dragging;
    var draggingDom = this.getDraggingDom();

    var dragStart = this.props.noDrag ? null : this.dragStart;

    return React.createElement(
      'div',
      { className: 'm-tree' },
      draggingDom,
      React.createElement(Node, {
        tree: tree,
        index: tree.getIndex(1),
        key: 1,
        paddingLeft: this.props.paddingLeft,
        onDragStart: dragStart,
        onCollapse: this.toggleCollapse,
        dragging: dragging && dragging.id
      })
    );
  },

  dragStart: function dragStart(id, dom, e) {
    this.dragging = {
      id: id,
      w: dom.offsetWidth,
      h: dom.offsetHeight,
      x: dom.offsetLeft,
      y: dom.offsetTop
    };

    this._startX = dom.offsetLeft;
    this._startY = dom.offsetTop;
    this._offsetX = e.clientX;
    this._offsetY = e.clientY;
    this._start = true;

    window.addEventListener('mousemove', this.drag);
    window.addEventListener('mouseup', this.dragEnd);
  },

  // oh
  drag: function drag(e) {
    if (this._start) {
      this.setState({
        dragging: this.dragging
      });
      this._start = false;
    }

    var tree = this.state.tree;
    var dragging = this.state.dragging;
    var paddingLeft = this.props.paddingLeft;
    var newIndex = null;
    var index = tree.getIndex(dragging.id);
    var collapsed = index.node.collapsed;

    var _startX = this._startX;
    var _startY = this._startY;
    var _offsetX = this._offsetX;
    var _offsetY = this._offsetY;

    var pos = {
      x: _startX + e.clientX - _offsetX,
      y: _startY + e.clientY - _offsetY
    };
    dragging.x = pos.x;
    dragging.y = pos.y;

    var diffX = dragging.x - paddingLeft / 2 - (index.left - 2) * paddingLeft;
    var diffY = dragging.y - dragging.h / 2 - (index.top - 2) * dragging.h;

    if (diffX < 0) {
      // left
      if (index.parent && !index.next) {
        newIndex = tree.move(index.id, index.parent, 'after');
      }
    } else if (diffX > paddingLeft) {
      // right
      if (index.prev && !tree.getIndex(index.prev).node.collapsed && !tree.getIndex(index.prev).node.leaf) {
        newIndex = tree.move(index.id, index.prev, 'append');
      }
    }

    if (newIndex) {
      index = newIndex;
      newIndex.node.collapsed = collapsed;
      dragging.id = newIndex.id;
    }

    if (diffY < 0) {
      // up
      var above = tree.getNodeByTop(index.top - 1);
      newIndex = tree.move(index.id, above.id, 'before');
    } else if (diffY > dragging.h) {
      // down
      if (index.next) {
        var below = tree.getIndex(index.next);
        if (below.children && below.children.length && !below.node.collapsed) {
          newIndex = tree.move(index.id, index.next, 'prepend');
        } else {
          newIndex = tree.move(index.id, index.next, 'after');
        }
      } else {
        var below = tree.getNodeByTop(index.top + index.height);
        if (below && below.parent !== index.id) {
          if (below.children && below.children.length) {
            newIndex = tree.move(index.id, below.id, 'prepend');
          } else {
            newIndex = tree.move(index.id, below.id, 'after');
          }
        }
      }
    }

    if (newIndex) {
      newIndex.node.collapsed = collapsed;
      dragging.id = newIndex.id;
    }

    this.setState({
      tree: tree,
      dragging: dragging
    });
  },

  dragEnd: function dragEnd() {
    var tree = this.state.tree,
        dragging = this.state.dragging,
        index = tree.getIndex(dragging.id),
        previousIndex = tree.getIndex(index.prev),
        parentIndex = tree.getIndex(index.parent),
        node = index.node,
        previousNode = null,
        parentNode = null;

    if (previousIndex)
      previousNode = previousIndex.node;
    if (parentIndex)
      parentNode = parentIndex.node;

    this.setState({
      dragging: {
        id: null,
        x: null,
        y: null,
        w: null,
        h: null
      }
    });

    this.change(parentNode, previousNode, node);
    window.removeEventListener('mousemove', this.drag);
    window.removeEventListener('mouseup', this.dragEnd);
  },

  change: function change(parentNode, previousNode, node) {
    this._updated = true;
    if (this.props.onChange) this.props.onChange(parentNode, previousNode, node);
  },

  toggleCollapse: function toggleCollapse(nodeId) {
    var tree = this.state.tree;
    var index = tree.getIndex(nodeId);
    var node = index.node;
    node.collapsed = !node.collapsed;
    tree.updateNodesPosition();

    this.setState({
      tree: tree
    });

    this.change(tree);
  }
});
<|endoftext|>


<commit_before>import React from 'react';
import { union, truncate, xor } from 'lodash';
import { connect } from 'react-redux';
import { compose, withState, withProps } from 'recompose';
import Table, { Tr, Td, Th } from '@ncigdc/uikit/Table';
import { withTheme } from '@ncigdc/theme';
import { Row } from '@ncigdc/uikit/Flex';
import withPropsOnChange from '@ncigdc/utils/withPropsOnChange';
import { getDefaultCurve } from '@ncigdc/utils/survivalplot';
import ExploreLink from '@ncigdc/components/Links/ExploreLink';
import Link from '@ncigdc/components/Links/Link';
import Venn, { buildOps } from '@ncigdc/components/Charts/Venn';
import withSize from '@ncigdc/utils/withSize';
import { stringifyJSONParam } from '@ncigdc/utils/uri';
import { COHORT_COMPARISON_FACETS } from '@ncigdc/utils/constants';
import CreateOrOpenAnalysis from '@ncigdc/components/CreateOrOpenAnalysis';
import Alias from '@ncigdc/components/Alias';
import Dropdown from '@ncigdc/uikit/Dropdown';
import Button from '@ncigdc/uikit/Button';
import { CaretIcon } from '@ncigdc/theme/icons';
import DropdownItem from '@ncigdc/uikit/DropdownItem';
import FacetTable from './FacetTable';
import Survival from './Survival';
import { getLowerAgeYears, getUpperAgeYears } from '@ncigdc/utils/ageDisplay';

const initialState = {
  loading: true,
};

const SET1_COLOUR = 'rgb(145, 114, 33)';
const SET2_COLOUR = 'rgb(29, 97, 135)';

const transformAgeAtDiagnosis = (buckets, compareBuckets) => {
  const unionWithCompareAndFillEmpties = () => {
    return union(
      buckets.map(({ key }) => key),
      compareBuckets.map(({ key }) => key),
    )
      .map(key => {
        const bucket = buckets.find(b => b.key === key);
        if (bucket) {
          return bucket;
        }
        return {
          key,
          doc_count: 0,
        };
      })
      .map(({ doc_count, key }) => ({
        doc_count,
        key: parseInt(key, 10),
      }));
  };

  const buildDisplayKeyAndFilters = (acc, { doc_count, key }) => {
    const displayRange = `${getLowerAgeYears(key)}${acc.nextAge === 0
      ? '+'
      : ' - ' + getUpperAgeYears(acc.nextAge)}`;
    return {
      nextAge: key,
      data: [
        ...acc.data,
        {
          doc_count,
          key: `${displayRange} years`,
          filters: [
            {
              op: '>=',
              content: {
                field: 'cases.diagnoses.age_at_diagnosis',
                value: [key],
              },
            },
            ...(acc.nextAge !== 0 && [
              {
                op: '<=',
                content: {
                  field: 'cases.diagnoses.age_at_diagnosis',
                  value: [acc.nextAge],
                },
              },
            ]),
          ],
        },
      ],
    };
  };
  return {
    buckets: unionWithCompareAndFillEmpties()
      .sort((a, b) => b.key - a.key) // iterate descending to populate nextAge
      .reduce(buildDisplayKeyAndFilters, { nextAge: 0, data: [] })
      .data.slice(0)
      .reverse(), // but display ascending
  };
};

export default compose(
  connect(),
  withState('survivalData', 'setSurvivalData', {}),
  withState('state', 'setState', initialState),
  withProps(({ setId1, setId2, setSurvivalData, setState }) => ({
    updateData: async () => {
      const survivalData = await getDefaultCurve({
        currentFilters: [
          {
            op: 'in',
            content: { field: 'cases.case_id', value: `set_id:${setId1}` },
          },
          {
            op: 'in',
            content: { field: 'cases.case_id', value: `set_id:${setId2}` },
          },
        ],
      });

      setSurvivalData(survivalData);

      setState(s => ({
        ...s,
        loading: false,
      }));
    },
  })),
  withPropsOnChange(['set1', 'set2'], ({ updateData }) => {
    updateData();
  }),
  withTheme,
  withSize(),
)(
  ({
    activeFacets,
    sets,
    setId1,
    setId2,
    setName1,
    setName2,
    theme,
    survivalData,
    viewer: { repository: { result1, result2 } },
    size: { width },
    message,
  }) => {
    const Set1 = (

        {truncate(setName1, { length: 50 })}

    );

    const Set2 = (

        {truncate(setName2, { length: 50 })}

    );

    const ops = buildOps({
      setIds: [setId1, setId2],
      type: 'case',
    });

    const availableFacets = Object.entries(COHORT_COMPARISON_FACETS);
    return (

        <Row
          style={{
            alignItems: 'center',
            margin: '20px 0',
            justifyContent: 'space-between',
          }}
        >

Cohort Comparison

            {message &&
{message}
}

          <Dropdown
            style={{ flex: 'none' }}
            autoclose={false}
            button={
              <Button>
                Choose Clinical Fields{' '}
                <CaretIcon style={{ marginLeft: 5 }} direction="down" />
              </Button>
            }
          >
            {availableFacets.map(([field, label]) => {
              return (
                <DropdownItem key={field} style={{ padding: 5 }}>
                  <Link
                    merge
                    query={{
                      activeFacets: stringifyJSONParam(
                        xor(activeFacets, [field]),
                      ),
                    }}
                  >

                      <input
                        readOnly
                        style={{ marginRight: 5, pointerEvents: 'none' }}
                        type="checkbox"
                        aira-label={`Select ${field}`}
                        checked={activeFacets.includes(field)}
                      />
                      {label}

                  </Link>
                </DropdownItem>
              );
            })}
          </Dropdown>
        </Row>
        <Row style={{ justifyContent: 'space-between', alignItems: 'center' }}>

            <Table
              style={{ width: '400px' }}
              headings={[

                  Selected Cohorts
                	,

                  # Cases
                	,
              ]}
              body={

                      <Alias i={1} style={{ fontWeight: 'bold' }} /> : {Set1}

                      <ExploreLink
                        query={{
                          searchTableTab: 'cases',
                          filters: {
                            op: 'AND',
                            content: [
                              {
                                op: 'IN',
                                content: {
                                  field: `cases.case_id`,
                                  value: [`set_id:${setId1}`],
                                },
                              },
                            ],
                          },
                        }}
                      >
                        {result1.hits.total.toLocaleString()}
                      </ExploreLink>

                      <Alias i={2} style={{ fontWeight: 'bold' }} /> : {Set2}

                      <ExploreLink
                        query={{
                          searchTableTab: 'cases',
                          filters: {
                            op: 'AND',
                            content: [
                              {
                                op: 'IN',
                                content: {
                                  field: `cases.case_id`,
                                  value: [`set_id:${setId2}`],
                                },
                              },
                            ],
                          },
                        }}
                      >
                        {result2.hits.total.toLocaleString()}
                      </ExploreLink>

              }
            />

              Cohorts Venn Diagram

              <CreateOrOpenAnalysis
                type="set_operations"
                sets={sets}
                style={{
                  color: theme.primary1,
                  fontSize: '0.8em',
                  textDecoration: 'underline',
                  display: 'inline-block',
                }}
              >
                Open in new tab
              </CreateOrOpenAnalysis>

            <Venn
              type="case"
              ops={ops}
              getFillColor={d => 'rgb(237, 237, 237)'}
              style={{
                fontSize: 10,
                width: 180,
                margin: 'auto',
                paddingTop: 5,
              }}
            />

        </Row>
        <Survival
          survivalData={survivalData}
          result1={result1}
          result2={result2}
          set1id={setId1}
          set2id={setId2}
          palette={[SET1_COLOUR, SET2_COLOUR]}
          style={{ marginTop: 10 }}
        />
        {availableFacets
          .filter(([field]) => activeFacets.includes(field))
          .map(([field, heading]) =>
            FacetTable({
              key: field,
              heading,
              Alias,
              field,
              data1: {
                ...JSON.parse(result1.facets),
                'diagnoses.age_at_diagnosis': transformAgeAtDiagnosis(
                  result1.aggregations.diagnoses__age_at_diagnosis.histogram
                    .buckets,
                  result2.aggregations.diagnoses__age_at_diagnosis.histogram
                    .buckets,
                ),
              },
              data2: {
                ...JSON.parse(result2.facets),
                'diagnoses.age_at_diagnosis': transformAgeAtDiagnosis(
                  result2.aggregations.diagnoses__age_at_diagnosis.histogram
                    .buckets,
                  result1.aggregations.diagnoses__age_at_diagnosis.histogram
                    .buckets,
                ),
              },
              result1,
              result2,
              set1: setId1,
              set2: setId2,
              setName1,
              setName2,
              palette: [SET1_COLOUR, SET2_COLOUR],
            }),
          )}

    );
  },
);
<commit_msg>🐛 [PRTL-1841] update survival graph on url change in comp (#2199)<commit_after>import React from 'react';
import { union, truncate, xor } from 'lodash';
import { connect } from 'react-redux';
import { compose, withState, withProps } from 'recompose';
import Table, { Tr, Td, Th } from '@ncigdc/uikit/Table';
import { withTheme } from '@ncigdc/theme';
import { Row } from '@ncigdc/uikit/Flex';
import withPropsOnChange from '@ncigdc/utils/withPropsOnChange';
import { getDefaultCurve } from '@ncigdc/utils/survivalplot';
import ExploreLink from '@ncigdc/components/Links/ExploreLink';
import Link from '@ncigdc/components/Links/Link';
import Venn, { buildOps } from '@ncigdc/components/Charts/Venn';
import withSize from '@ncigdc/utils/withSize';
import { stringifyJSONParam } from '@ncigdc/utils/uri';
import { COHORT_COMPARISON_FACETS } from '@ncigdc/utils/constants';
import CreateOrOpenAnalysis from '@ncigdc/components/CreateOrOpenAnalysis';
import Alias from '@ncigdc/components/Alias';
import Dropdown from '@ncigdc/uikit/Dropdown';
import Button from '@ncigdc/uikit/Button';
import { CaretIcon } from '@ncigdc/theme/icons';
import DropdownItem from '@ncigdc/uikit/DropdownItem';
import FacetTable from './FacetTable';
import Survival from './Survival';
import { getLowerAgeYears, getUpperAgeYears } from '@ncigdc/utils/ageDisplay';
import withRouter from '@ncigdc/utils/withRouter';

const initialState = {
  loading: true,
};

const SET1_COLOUR = 'rgb(145, 114, 33)';
const SET2_COLOUR = 'rgb(29, 97, 135)';

const transformAgeAtDiagnosis = (buckets, compareBuckets) => {
  const unionWithCompareAndFillEmpties = () => {
    return union(
      buckets.map(({ key }) => key),
      compareBuckets.map(({ key }) => key),
    )
      .map(key => {
        const bucket = buckets.find(b => b.key === key);
        if (bucket) {
          return bucket;
        }
        return {
          key,
          doc_count: 0,
        };
      })
      .map(({ doc_count, key }) => ({
        doc_count,
        key: parseInt(key, 10),
      }));
  };

  const buildDisplayKeyAndFilters = (acc, { doc_count, key }) => {
    const displayRange = `${getLowerAgeYears(key)}${acc.nextAge === 0
      ? '+'
      : ' - ' + getUpperAgeYears(acc.nextAge)}`;
    return {
      nextAge: key,
      data: [
        ...acc.data,
        {
          doc_count,
          key: `${displayRange} years`,
          filters: [
            {
              op: '>=',
              content: {
                field: 'cases.diagnoses.age_at_diagnosis',
                value: [key],
              },
            },
            ...(acc.nextAge !== 0 && [
              {
                op: '<=',
                content: {
                  field: 'cases.diagnoses.age_at_diagnosis',
                  value: [acc.nextAge],
                },
              },
            ]),
          ],
        },
      ],
    };
  };
  return {
    buckets: unionWithCompareAndFillEmpties()
      .sort((a, b) => b.key - a.key) // iterate descending to populate nextAge
      .reduce(buildDisplayKeyAndFilters, { nextAge: 0, data: [] })
      .data.slice(0)
      .reverse(), // but display ascending
  };
};

export default compose(
  connect(),
  withState('survivalData', 'setSurvivalData', {}),
  withState('state', 'setState', initialState),
  withProps({
    updateData: async ({ setId1, setId2, setSurvivalData, setState }) => {
      const survivalData = await getDefaultCurve({
        currentFilters: [
          {
            op: 'in',
            content: { field: 'cases.case_id', value: `set_id:${setId1}` },
          },
          {
            op: 'in',
            content: { field: 'cases.case_id', value: `set_id:${setId2}` },
          },
        ],
      });

      setSurvivalData(survivalData);

      setState(s => ({
        ...s,
        loading: false,
      }));
    },
  }),
  withRouter,
  withPropsOnChange(
    ['set1', 'set2', 'location'],
    ({ updateData, ...props }) => {
      updateData(props);
    },
  ),
  withTheme,
  withSize(),
)(
  ({
    activeFacets,
    sets,
    setId1,
    setId2,
    setName1,
    setName2,
    theme,
    survivalData,
    viewer: { repository: { result1, result2 } },
    size: { width },
    message,
  }) => {
    const Set1 = (

        {truncate(setName1, { length: 50 })}

    );

    const Set2 = (

        {truncate(setName2, { length: 50 })}

    );

    const ops = buildOps({
      setIds: [setId1, setId2],
      type: 'case',
    });

    const availableFacets = Object.entries(COHORT_COMPARISON_FACETS);
    return (

        <Row
          style={{
            alignItems: 'center',
            margin: '20px 0',
            justifyContent: 'space-between',
          }}
        >

Cohort Comparison

            {message &&
{message}
}

          <Dropdown
            style={{ flex: 'none' }}
            autoclose={false}
            button={
              <Button>
                Choose Clinical Fields{' '}
                <CaretIcon style={{ marginLeft: 5 }} direction="down" />
              </Button>
            }
          >
            {availableFacets.map(([field, label]) => {
              return (
                <DropdownItem key={field} style={{ padding: 5 }}>
                  <Link
                    merge
                    query={{
                      activeFacets: stringifyJSONParam(
                        xor(activeFacets, [field]),
                      ),
                    }}
                  >

                      <input
                        readOnly
                        style={{ marginRight: 5, pointerEvents: 'none' }}
                        type="checkbox"
                        aira-label={`Select ${field}`}
                        checked={activeFacets.includes(field)}
                      />
                      {label}

                  </Link>
                </DropdownItem>
              );
            })}
          </Dropdown>
        </Row>
        <Row style={{ justifyContent: 'space-between', alignItems: 'center' }}>

            <Table
              style={{ width: '400px' }}
              headings={[

                  Selected Cohorts
                	,

                  # Cases
                	,
              ]}
              body={

                      <Alias i={1} style={{ fontWeight: 'bold' }} /> : {Set1}

                      <ExploreLink
                        query={{
                          searchTableTab: 'cases',
                          filters: {
                            op: 'AND',
                            content: [
                              {
                                op: 'IN',
                                content: {
                                  field: `cases.case_id`,
                                  value: [`set_id:${setId1}`],
                                },
                              },
                            ],
                          },
                        }}
                      >
                        {result1.hits.total.toLocaleString()}
                      </ExploreLink>

                      <Alias i={2} style={{ fontWeight: 'bold' }} /> : {Set2}

                      <ExploreLink
                        query={{
                          searchTableTab: 'cases',
                          filters: {
                            op: 'AND',
                            content: [
                              {
                                op: 'IN',
                                content: {
                                  field: `cases.case_id`,
                                  value: [`set_id:${setId2}`],
                                },
                              },
                            ],
                          },
                        }}
                      >
                        {result2.hits.total.toLocaleString()}
                      </ExploreLink>

              }
            />

              Cohorts Venn Diagram

              <CreateOrOpenAnalysis
                type="set_operations"
                sets={sets}
                style={{
                  color: theme.primary1,
                  fontSize: '0.8em',
                  textDecoration: 'underline',
                  display: 'inline-block',
                }}
              >
                Open in new tab
              </CreateOrOpenAnalysis>

            <Venn
              type="case"
              ops={ops}
              getFillColor={d => 'rgb(237, 237, 237)'}
              style={{
                fontSize: 10,
                width: 180,
                margin: 'auto',
                paddingTop: 5,
              }}
            />

        </Row>
        <Survival
          survivalData={survivalData}
          result1={result1}
          result2={result2}
          set1id={setId1}
          set2id={setId2}
          palette={[SET1_COLOUR, SET2_COLOUR]}
          style={{ marginTop: 10 }}
        />
        {availableFacets
          .filter(([field]) => activeFacets.includes(field))
          .map(([field, heading]) =>
            FacetTable({
              key: field,
              heading,
              Alias,
              field,
              data1: {
                ...JSON.parse(result1.facets),
                'diagnoses.age_at_diagnosis': transformAgeAtDiagnosis(
                  result1.aggregations.diagnoses__age_at_diagnosis.histogram
                    .buckets,
                  result2.aggregations.diagnoses__age_at_diagnosis.histogram
                    .buckets,
                ),
              },
              data2: {
                ...JSON.parse(result2.facets),
                'diagnoses.age_at_diagnosis': transformAgeAtDiagnosis(
                  result2.aggregations.diagnoses__age_at_diagnosis.histogram
                    .buckets,
                  result1.aggregations.diagnoses__age_at_diagnosis.histogram
                    .buckets,
                ),
              },
              result1,
              result2,
              set1: setId1,
              set2: setId2,
              setName1,
              setName2,
              palette: [SET1_COLOUR, SET2_COLOUR],
            }),
          )}

    );
  },
);
<|endoftext|>


<commit_before>exports.email = /^(?:[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+\.)*[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+@(?:(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-](?!\.)){0,61}[a-zA-Z0-9]?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9\-](?!$)){0,61}[a-zA-Z0-9]?)|(?:\[(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\]))$/;
exports.url = /^(?:(?:ht|f)tp(?:s?)\:\/\/|~\/|\/)?(?:\w+:\w+@)?((?:(?:[-\w\d{1-3}]+\.)+(?:com|org|net|gov|mil|biz|info|mobi|name|aero|jobs|edu|co\.uk|ac\.uk|it|fr|tv|museum|asia|local|travel|[a-z]{2}))|((\b25[0-5]\b|\b[2][0-4][0-9]\b|\b[0-1]?[0-9]?[0-9]\b)(\.(\b25[0-5]\b|\b[2][0-4][0-9]\b|\b[0-1]?[0-9]?[0-9]\b)){3}))(?::[\d]{1,5})?(?:(?:(?:\/(?:[-\w~!$+|.,=]|%[a-f\d]{2})+)+|\/)+|\?|#)?(?:(?:\?(?:[-\w~!$+|.,*:]|%[a-f\d{2}])+=?(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)(?:&(?:[-\w~!$+|.,*:]|%[a-f\d{2}])+=?(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)*)*(?:#(?:[-\w~!$ |\/.,*:;=]|%[a-f\d]{2})*)?$/i;
exports.urlsafe = /^[^&$+,\/:=?@ <>\[\]\{\}\\^~%#]+$/;
exports.hexColor = /^\#[0-9a-fA-F]{6}$/;
exports.names = /^[a-zA-ZÁÉÍÓÚáéíóúÀÈÌÒÙàèìòùÄËÏÖÜäëïöüÇçÑñ\s]+$/;
exports.username = /^\w{4,15}$/;
exports.blank = /^\s+$/;
exports.password = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\s).{6,}$/;
exports.numeric = /^[0-9]+$/;<commit_msg>[regexps] - Fix passowrd regexp<commit_after>exports.email = /^(?:[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+\.)*[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+@(?:(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-](?!\.)){0,61}[a-zA-Z0-9]?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9\-](?!$)){0,61}[a-zA-Z0-9]?)|(?:\[(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\]))$/;
exports.url = /^(?:(?:ht|f)tp(?:s?)\:\/\/|~\/|\/)?(?:\w+:\w+@)?((?:(?:[-\w\d{1-3}]+\.)+(?:com|org|net|gov|mil|biz|info|mobi|name|aero|jobs|edu|co\.uk|ac\.uk|it|fr|tv|museum|asia|local|travel|[a-z]{2}))|((\b25[0-5]\b|\b[2][0-4][0-9]\b|\b[0-1]?[0-9]?[0-9]\b)(\.(\b25[0-5]\b|\b[2][0-4][0-9]\b|\b[0-1]?[0-9]?[0-9]\b)){3}))(?::[\d]{1,5})?(?:(?:(?:\/(?:[-\w~!$+|.,=]|%[a-f\d]{2})+)+|\/)+|\?|#)?(?:(?:\?(?:[-\w~!$+|.,*:]|%[a-f\d{2}])+=?(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)(?:&(?:[-\w~!$+|.,*:]|%[a-f\d{2}])+=?(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)*)*(?:#(?:[-\w~!$ |\/.,*:;=]|%[a-f\d]{2})*)?$/i;
exports.urlsafe = /^[^&$+,\/:=?@ <>\[\]\{\}\\^~%#]+$/;
exports.hexColor = /^\#[0-9a-fA-F]{6}$/;
exports.names = /^[a-zA-ZÁÉÍÓÚáéíóúÀÈÌÒÙàèìòùÄËÏÖÜäëïöüÇçÑñ\s]+$/;
exports.username = /^\w{4,15}$/;
exports.blank = /^\s+$/;
exports.password = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\s).{4,}$/;
exports.numeric = /^[0-9]+$/;<|endoftext|>


<commit_before>/*! Teuthis XHR proxy/cache

This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
'use strict';

var _ = require('lodash/core');
_.isArrayBuffer = require('lodash/isArrayBuffer');
var localforage = require('localforage');

// Provides class RequestCache, a wrapper around the localforage local storage provider
// that manages generating keys from XHR requests, and querying and saving data into the cache

var defaultOptions = {
  instanceName: null,
  instanceDescription: 'Teuthis XHR proxy cache',
  keyPrefix: '',
  onStatus: null,
  onReady: null,
  debugCachePuts: false,
  debugCacheHits: false,
  debugCacheMiss: false,
  debugCacheBoot: false,
};

// Create a new RequestCache
// If options.instanceName is set and not null then use a new private scope of localforage of that name, otherwise use global localforage
// Using instanceName changes the behaviour of clear() to be less polite
function RequestCache(options) {
  console.log('[Teuthis] RequestCache constructor');
  var self = this;
  this.stats = {miss: 0, hits: 0, memory: 0};
  this.options = _.defaults({}, options);  _.defaults(this.options, defaultOptions);
  console.log('RequestCache: Options=' + JSON.stringify(this.options));
  this.store = localforage;
  this.ownStore = false;
  if (this.options.instanceName !== null) {
    this.ownStore = true;
    this.store = localforage.createInstance({name: this.options.instanceName, description: this.options.instanceDescription});
  }

  // Keep our own list of keys, so we can flush them from localforage without
  // flushing other items that are not ours
  this.keyPrefix = (typeof this.options.keyprefix === 'string') ? this.options.keyprefix : '';
  this.cacheKeys = {};

  // If we have a key prefix or are using own store, then propulate cacheKeys
  // This is problematic, we cant guarantee that when the constructor returns, we are ready!
  this.ready = false;
  this.store.iterate(function(v, k) {
    if (self.ownStore || self.keyIsPrefixed(k)) {
      self.cacheKeys[k] = true;
      var m = 0;
      if (typeof v === 'string') m = v.length;
      else if (_.isArrayBuffer(v)) m = v.byteLength;
      // THis is a phenomenally bad leaky abstraction...
      else if (_.has(v, 'v')) m = v.v.size;
      //else console.log(v);
      self.stats.memory += m;
      if (self.options.debugCacheBoot) console.log('[Teuthis] found key: ' + k + ', memory: ' + m + '/' + self.stats.memory + ', ' + typeof v);
    }
  }, function() {
    console.log('[Teuthis] found keys: ' + Object.getOwnPropertyNames(self.cacheKeys).length);
    console.log('[Teuthis] found memory: ' + self.stats.memory);
    self.ready = true;
    if (self.options.onReady) self.options.onReady();
  });
}

function handleCacheMiss(key, onMiss) {
  if (this.options.debugCacheMiss) console.log('[Teuthis] proxy-miss ' + key);
  this.stats.miss ++;
  if (_.isFunction(onMiss)) onMiss(key);
  if (_.isFunction(this.options.onStatus)) this.options.onStatus.call(this);
}

function handleCacheHit(key, cachedValue, onHit) {
  if (this.options.debugCacheHits) console.log('[Teuthis] proxy-hit ' + key);
  this.stats.hits ++;
  if (_.isFunction(onHit)) onHit(key, cachedValue);
  if (_.isFunction(this.options.onStatus)) this.options.onStatus.call(this);
}

// Returns estimated number of entries in the cache
// If someone cleared the localforage instance in the meantime, number will be incorrect
RequestCache.prototype.weakLength = function() {
  return Object.getOwnPropertyNames(this.cacheKeys).length;
}

RequestCache.prototype.composeKey = function(method, url) {
  return this.keyPrefix + method + '__' + url;
}

RequestCache.prototype.keyIsPrefixed = function(key) {
  if (this.keyPrefix && this.keyPrefix.length > 0) {
    return key.startsWith(this.keyPrefix);
  } else {
    return false;
  }
}

// Reset statistical information (other than memory usage)
RequestCache.prototype.clearStats = function() {
  this.stats.miss = 0;
  this.stats.hits = 0;
}

RequestCache.prototype.getStats = function() {
  return Object.assign({}, this.stats);
}

RequestCache.prototype.setDebugOptions = function(options) {
  if (_.has(options, 'debugCachePuts')) this.options.debugCachePuts = options.debugCachePuts;
  if (_.has(options, 'debugCacheHits')) this.options.debugCacheHits = options.debugCacheHits;
  if (_.has(options, 'debugCacheMiss')) this.options.debugCacheMiss = options.debugCacheMiss;
  if (_.has(options, 'debugCacheBoot')) this.options.debugCacheBoot = options.debugCacheBoot;
}

RequestCache.prototype.purgeItem = function(key, done) {
  var self = this;
  this.store.removeItem(k, function() {
    if (self && self.cacheKeys && self.cacheKeys.hasOwnProperty(k)) {
      delete self.cacheKeys[k];
    }
    if (done) done();
  });
}

// Clear all our entries from the localforage instance
// Probably slower than localforage.clear() but guarantee to remove only our entries
RequestCache.prototype.flush = function(done) {
  var self = this;
  if (this.ownStore) {
    self.store.clear(function() { self.cacheKeys = {}; self.stats.memory = 0; console.log('[Teuthis] proxy-flush'); if (done) done(); });
  } else {
    // Try and remove keys we know about, or with our prefix
    self.store.iterate(function(v, k) {
      if (self.cacheKeys.hasOwnProperty(k) || self.keyIsPrefixed(k)) {
        self.store.removeItem(k, function() { delete self.cacheKeys[k]; });
      }
    }, function() {
      self.cacheKeys = {};
      self.stats.memory = 0;
      console.log('[Teuthis] proxy-flush');
      if (done) { done(); }
    });
  }
}

RequestCache.prototype.each = function(cb, done) {
  var self = this;
  self.store.iterate(function(v, k) {
    if (self.cacheKeys.hasOwnProperty(k) || self.keyIsPrefixed(k)) {
      cb(k, v);
    }
  }, done);
}

// Weakly check if object is cached. Only checks our key list, not localforage itself
// So does not guarantee match(...) will have a HIT if, say, someone cleared localforage
RequestCache.prototype.weakHas = function(method, url) {
  var key = this.composeKey(method, url);
  return this.cacheKeys.hasOwnProperty(key);
}

// If method:url is in localforage then call onHit(composedKey, response) else call onMiss(composedKey)
RequestCache.prototype.match = function(method, url, onHit, onMiss) {
  var key = this.composeKey(method, url);
  var self = this;
  this.store.getItem(key)
    .then(function(cachedValue) {
      try {
        if (cachedValue === null) {
          delete self.cacheKeys[key]; // Handle the case where something else managed to delete an entry from localforage
          handleCacheMiss.call(self, key, onMiss);
        } else {
          handleCacheHit.call(self, key, cachedValue, onHit);
        }
      } catch (err) {
        // callback was source of the error, not this.store.getItem
        console.error('[Teuthis] proxy-cache-match handler error ' + err);
        console.error(err);
        delete self.cacheKeys[key];
      }
    }).catch(function(err) {
      // care - this will catch errors in the handler, not just errors in the cache itself
      //      - if we are not careful by having try/catch above
      //      - i.e. we need to avoid a double call to handleCacheMiss
      // otherwise we see -
      //    Error: Uncaught (in promise): InvalidStateError: XMLHttpRequest state must be OPENED.
      //    Derived from xhr.send.apply(xhr, arguments); in send() inside the miss callback
      console.error('[Teuthis] proxy-cache-match error ' + err);
      console.error(err);
      delete self.cacheKeys[key];
      handleCacheMiss.call(self, key, onMiss);
    });
}

// Put value of response for method:url into localforage, and call done(), or call done(err) if an error happens
RequestCache.prototype.put = function(method, url, value, done) {
  var key = this.composeKey(method, url);
  if (this.options.debugCachePuts) console.log('[Teuthis] proxy-cache-put ' + key);
  var self = this;
  this.store.setItem(key, value).then(function() {
    self.cacheKeys[key] = true;
    if (typeof value === 'string') self.stats.memory += value.length;
    else if (_.isArrayBuffer(value)) self.stats.memory += value.byteLength;
    if (done) done();
  }).catch(function(err) {
    console.error('[Teuthis] proxy-cache-put error ' + err);
    if (done) done(err);
  });
}

RequestCache.prototype.forceClear = function() { this.store.clear(); }

module.exports = RequestCache;<commit_msg>Fix computation of space at boot<commit_after>/*! Teuthis XHR proxy/cache

This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
'use strict';

var _ = require('lodash/core');
_.isArrayBuffer = require('lodash/isArrayBuffer');
var localforage = require('localforage');

// Provides class RequestCache, a wrapper around the localforage local storage provider
// that manages generating keys from XHR requests, and querying and saving data into the cache

var defaultOptions = {
  instanceName: null,
  instanceDescription: 'Teuthis XHR proxy cache',
  keyPrefix: '',
  onStatus: null,
  onReady: null,
  debugCachePuts: false,
  debugCacheHits: false,
  debugCacheMiss: false,
  debugCacheBoot: false,
};

// Create a new RequestCache
// If options.instanceName is set and not null then use a new private scope of localforage of that name, otherwise use global localforage
// Using instanceName changes the behaviour of clear() to be less polite
function RequestCache(options) {
  console.log('[Teuthis] RequestCache constructor');
  var self = this;
  this.stats = {miss: 0, hits: 0, memory: 0};
  this.options = _.defaults({}, options);  _.defaults(this.options, defaultOptions);
  console.log('RequestCache: Options=' + JSON.stringify(this.options));
  this.store = localforage;
  this.ownStore = false;
  if (this.options.instanceName !== null) {
    this.ownStore = true;
    this.store = localforage.createInstance({name: this.options.instanceName, description: this.options.instanceDescription});
  }

  // Keep our own list of keys, so we can flush them from localforage without
  // flushing other items that are not ours
  this.keyPrefix = (typeof this.options.keyprefix === 'string') ? this.options.keyprefix : '';
  this.cacheKeys = {};

  // If we have a key prefix or are using own store, then propulate cacheKeys
  // This is problematic, we cant guarantee that when the constructor returns, we are ready!
  this.ready = false;
  var d0 = Date.now();
  this.store.iterate(function(v, k) {
    if (self.ownStore || self.keyIsPrefixed(k)) {
      self.cacheKeys[k] = true;
      var m = 0;
      // This is a phenomenally bad leaky abstraction...
      var vd = _.has(v, 'v') ? v.v : v;
      var age = _.has(v, 'ts') ? ((d0 - v.ts) / 60 / 60 / 24).toFixed(1) : 0;
      if (typeof vd === 'string') m = vd.length;
      else if (_.isArrayBuffer(vd)) m = vd.byteLength;
      //else console.log(v);
      self.stats.memory += m;
      if (self.options.debugCacheBoot) {
        console.log('[Teuthis] found key: ' + k + ', memory: ' + m + '/' + self.stats.memory + ', ' + typeof vd + ', ' + age + ' days');
      }
    }
  }, function() {
    console.log('[Teuthis] found keys: ' + Object.getOwnPropertyNames(self.cacheKeys).length);
    console.log('[Teuthis] found memory: ' + self.stats.memory);
    self.ready = true;
    if (self.options.onReady) self.options.onReady();
  });
}

function handleCacheMiss(key, onMiss) {
  if (this.options.debugCacheMiss) console.log('[Teuthis] proxy-miss ' + key);
  this.stats.miss ++;
  if (_.isFunction(onMiss)) onMiss(key);
  if (_.isFunction(this.options.onStatus)) this.options.onStatus.call(this);
}

function handleCacheHit(key, cachedValue, onHit) {
  if (this.options.debugCacheHits) console.log('[Teuthis] proxy-hit ' + key);
  this.stats.hits ++;
  if (_.isFunction(onHit)) onHit(key, cachedValue);
  if (_.isFunction(this.options.onStatus)) this.options.onStatus.call(this);
}

// Returns estimated number of entries in the cache
// If someone cleared the localforage instance in the meantime, number will be incorrect
RequestCache.prototype.weakLength = function() {
  return Object.getOwnPropertyNames(this.cacheKeys).length;
}

RequestCache.prototype.composeKey = function(method, url) {
  return this.keyPrefix + method + '__' + url;
}

RequestCache.prototype.keyIsPrefixed = function(key) {
  if (this.keyPrefix && this.keyPrefix.length > 0) {
    return key.startsWith(this.keyPrefix);
  } else {
    return false;
  }
}

// Reset statistical information (other than memory usage)
RequestCache.prototype.clearStats = function() {
  this.stats.miss = 0;
  this.stats.hits = 0;
}

RequestCache.prototype.getStats = function() {
  return Object.assign({}, this.stats);
}

RequestCache.prototype.setDebugOptions = function(options) {
  if (_.has(options, 'debugCachePuts')) this.options.debugCachePuts = options.debugCachePuts;
  if (_.has(options, 'debugCacheHits')) this.options.debugCacheHits = options.debugCacheHits;
  if (_.has(options, 'debugCacheMiss')) this.options.debugCacheMiss = options.debugCacheMiss;
  if (_.has(options, 'debugCacheBoot')) this.options.debugCacheBoot = options.debugCacheBoot;
}

RequestCache.prototype.purgeItem = function(key, done) {
  var self = this;
  this.store.removeItem(k, function() {
    if (self && self.cacheKeys && self.cacheKeys.hasOwnProperty(k)) {
      delete self.cacheKeys[k];
    }
    if (done) done();
  });
}

// Clear all our entries from the localforage instance
// Probably slower than localforage.clear() but guarantee to remove only our entries
RequestCache.prototype.flush = function(done) {
  var self = this;
  if (this.ownStore) {
    self.store.clear(function() { self.cacheKeys = {}; self.stats.memory = 0; console.log('[Teuthis] proxy-flush'); if (done) done(); });
  } else {
    // Try and remove keys we know about, or with our prefix
    self.store.iterate(function(v, k) {
      if (self.cacheKeys.hasOwnProperty(k) || self.keyIsPrefixed(k)) {
        self.store.removeItem(k, function() { delete self.cacheKeys[k]; });
      }
    }, function() {
      self.cacheKeys = {};
      self.stats.memory = 0;
      console.log('[Teuthis] proxy-flush');
      if (done) { done(); }
    });
  }
}

RequestCache.prototype.each = function(cb, done) {
  var self = this;
  self.store.iterate(function(v, k) {
    if (self.cacheKeys.hasOwnProperty(k) || self.keyIsPrefixed(k)) {
      cb(k, v);
    }
  }, done);
}

// Weakly check if object is cached. Only checks our key list, not localforage itself
// So does not guarantee match(...) will have a HIT if, say, someone cleared localforage
RequestCache.prototype.weakHas = function(method, url) {
  var key = this.composeKey(method, url);
  return this.cacheKeys.hasOwnProperty(key);
}

// If method:url is in localforage then call onHit(composedKey, response) else call onMiss(composedKey)
RequestCache.prototype.match = function(method, url, onHit, onMiss) {
  var key = this.composeKey(method, url);
  var self = this;
  this.store.getItem(key)
    .then(function(cachedValue) {
      try {
        if (cachedValue === null) {
          delete self.cacheKeys[key]; // Handle the case where something else managed to delete an entry from localforage
          handleCacheMiss.call(self, key, onMiss);
        } else {
          handleCacheHit.call(self, key, cachedValue, onHit);
        }
      } catch (err) {
        // callback was source of the error, not this.store.getItem
        console.error('[Teuthis] proxy-cache-match handler error ' + err);
        console.error(err);
        delete self.cacheKeys[key];
      }
    }).catch(function(err) {
      // care - this will catch errors in the handler, not just errors in the cache itself
      //      - if we are not careful by having try/catch above
      //      - i.e. we need to avoid a double call to handleCacheMiss
      // otherwise we see -
      //    Error: Uncaught (in promise): InvalidStateError: XMLHttpRequest state must be OPENED.
      //    Derived from xhr.send.apply(xhr, arguments); in send() inside the miss callback
      console.error('[Teuthis] proxy-cache-match error ' + err);
      console.error(err);
      delete self.cacheKeys[key];
      handleCacheMiss.call(self, key, onMiss);
    });
}

// Put value of response for method:url into localforage, and call done(), or call done(err) if an error happens
RequestCache.prototype.put = function(method, url, value, done) {
  var key = this.composeKey(method, url);
  if (this.options.debugCachePuts) console.log('[Teuthis] proxy-cache-put ' + key);
  var self = this;
  this.store.setItem(key, value).then(function() {
    self.cacheKeys[key] = true;
    if (typeof value === 'string') self.stats.memory += value.length;
    else if (_.isArrayBuffer(value)) self.stats.memory += value.byteLength;
    if (done) done();
  }).catch(function(err) {
    console.error('[Teuthis] proxy-cache-put error ' + err);
    if (done) done(err);
  });
}

RequestCache.prototype.forceClear = function() { this.store.clear(); }

module.exports = RequestCache;<|endoftext|>


<commit_before>const fs = require('fs')
const request = require('./promise-request')
const Url = require('./url')

async function getPhpSessionID(jar) {
  let { response: { headers } } = await request(Url.Base)
  jar.add(headers['set-cookie'])
}

async function downloadCaptureImage(jar) {
  let { response, body } = await request(Url.CaptureCode, {
    headers: { cookie: jar.toString() },
    encoding: null
  })
  return new Promise((resolve, reject) => {
    fs.writeFile('check.png', body, { encoding: 'binary' }, error => error ? reject(error) : resolve())
  })
}

async function login(form, jar) {
  let { response: { headers }, body } = await request(Url.Login, {
    method: 'POST',
    headers: { cookie: jar.toString() },
    form,
    json: true
  })
  jar.add(headers['set-cookie'])
  return body.status === 1
}

module.exports = {
  getPhpSessionID,
  downloadCaptureImage,
  login
}<commit_msg>'User.login' returns more information now<commit_after>const fs = require('fs')
const request = require('./promise-request')
const Url = require('./url')

async function getPhpSessionID(jar) {
  let { response: { headers } } = await request(Url.Base)
  jar.add(headers['set-cookie'])
}

async function downloadCaptureImage(jar) {
  let { response, body } = await request(Url.CaptureCode, {
    headers: { cookie: jar.toString() },
    encoding: null
  })
  return new Promise((resolve, reject) => {
    fs.writeFile('check.png', body, { encoding: 'binary' }, error => error ? reject(error) : resolve())
  })
}

async function login(form, jar) {
  let { response: { headers }, body } = await request(Url.Login, {
    method: 'POST',
    headers: { cookie: jar.toString() },
    form,
    json: true
  })

  jar.add(headers['set-cookie'])

  return {
    success: body.status === 1,
    serverMessage: body.msg,
    rawUserInfo: body.status === 1 ? body.data.list : null,
    rawSessionData: body.status === 1 ? body.data._hash_ : null
  }
}

module.exports = {
  getPhpSessionID,
  downloadCaptureImage,
  login
}<|endoftext|>


<commit_before>function requireDependencies(deps, cb) {
    deps = Array.isArray(deps) ? deps : [deps];

    beforeEach(function () {
        var done = false;
        runs(function () {
            require(deps, function () {
                cb && cb.apply(cb, arguments);
                done = true;
            });
        });
        waitsFor(function () {
            return done;
        });
    });
}

// Allows me to specify stubs to return from a require
function requireStubs(stubs) {
    spyOn(window, 'require').andCallFake(function (deps, cb) {
        if (Array.isArray(deps) && deps.some(function (dep) {
            return stubs[dep.replace(/.*\//, '')]
        })) {
            var retDeps = deps.map(function (dep) {
                return stubs[dep.replace(/.*\//, '')];
            })
            cb && cb.apply(cb, retDeps);
        } else {
            return window.require.originalValue.apply(window.require, arguments);
        }
    });
}

<commit_msg>Do not use JS 1.8 features in test framework<commit_after>function requireDependencies(deps, cb) {
    var is_array;
    if (Array.isArray!==undefined)
        is_array=Array.isArray(deps);
    else
        is_array=Object.prototype.toString.call(deps)==="[object Array]";

    if (!is_array)
        deps=[deps];

    beforeEach(function () {
        var done = false;
        runs(function () {
            require(deps, function () {
                cb && cb.apply(cb, arguments);
                done = true;
            });
        });
        waitsFor(function () {
            return done;
        });
    });
}

// Allows me to specify stubs to return from a require
function requireStubs(stubs) {
    spyOn(window, 'require').andCallFake(function (deps, cb) {
        if (Array.isArray(deps) && deps.some(function (dep) {
            return stubs[dep.replace(/.*\//, '')]
        })) {
            var retDeps = deps.map(function (dep) {
                return stubs[dep.replace(/.*\//, '')];
            })
            cb && cb.apply(cb, retDeps);
        } else {
            return window.require.originalValue.apply(window.require, arguments);
        }
    });
}

<|endoftext|>


<commit_before>'use strict';

process.env.BABEL_ENV = 'production';
process.env.NODE_ENV = 'production';

const chalk = require('chalk');
const webpack = require('webpack');

let config = require('../config/webpack.config.prod');
let compiler = webpack(config);

let lastBuildStateHash = null;
compiler.run(function (err, stats) {
    // wait fix bug "Multiple compilation triggered in webpack2 watch mode"
    // https://github.com/webpack/webpack.js.org/issues/1096
    // https://runkit.com/kidney/multiple-compilation-triggered-in-webpack2-watch-mode
    if (lastBuildStateHash !== stats.hash) {
        lastBuildStateHash = stats.hash;
    }
});
<commit_msg>feat: build流程（未完成）<commit_after>'use strict';

process.env.BABEL_ENV = 'production';
process.env.NODE_ENV = 'production';

const chalk = require('chalk');
const webpack = require('webpack');

let config = require('../config/webpack.config.prod');
let compiler = webpack(config);

let lastBuildStateHash = null;
compiler.run(function (err, stats) {
    // wait fix bug "Multiple compilation triggered in webpack2 watch mode"
    // https://github.com/webpack/webpack.js.org/issues/1096
    // https://runkit.com/kidney/multiple-compilation-triggered-in-webpack2-watch-mode
    if (lastBuildStateHash !== stats.hash) {
        lastBuildStateHash = stats.hash;

        if (warnings.length) {
            console.log(chalk.yellow('Compiled with warnings.\n'));
            console.log(warnings.join('\n\n'));
            console.log(
                '\nSearch for the ' +
                chalk.underline(chalk.yellow('keywords')) +
                ' to learn more about each warning.'
            );
            console.log(
                'To ignore, add ' +
                chalk.cyan('// eslint-disable-next-line') +
                ' to the line before.\n'
            );
        } else {
            console.log(chalk.green('Compiled successfully.\n'));
        }
    }
});
<|endoftext|>


<commit_before>(function() {
    'use strict';

    var DIR         = '../',
        DIR_SERVER  = DIR + 'server/',

        isWin       = process.platform === 'win32',
        Util        = require(DIR           + 'util'),
        commander   = require(DIR_SERVER    + 'commander');

    exports.read            = read;
    exports.convertPath     = convertPath;

    function read(path, callback) {
        if (isWin && path === '/')
            getRoot(callback);
        else
            commander.getDirContent(path, callback);
    }

    function getRoot(callback) {
        var win = require(DIR_SERVER + 'win');

        win.getVolumes(function(error, volumes) {
            var data = {
                path    : '/',
                files   : []
            };

            if (!error)
                data.files = volumes.map(function(volume) {
                    return {
                        name: volume,
                        size: 0,
                        mode: 0,
                        owner: 0
                    };
                });

            callback(error, data);
        });
    }

    function convertPath(path) {
        var volume;

        Util.checkArgs(arguments, ['path']);

        if (isWin && path !== '/') {
            volume  = path[1];
            path    = path.split('')
                          .slice(2)
                          .join('');

            path    = volume + ':' + path;
        }

        return path;
    }
})();
<commit_msg>fix(mellow) getRoot size: 0 -> dir<commit_after>(function() {
    'use strict';

    var DIR         = '../',
        DIR_SERVER  = DIR + 'server/',

        isWin       = process.platform === 'win32',
        Util        = require(DIR           + 'util'),
        commander   = require(DIR_SERVER    + 'commander');

    exports.read            = read;
    exports.convertPath     = convertPath;

    function read(path, callback) {
        if (isWin && path === '/')
            getRoot(callback);
        else
            commander.getDirContent(path, callback);
    }

    function getRoot(callback) {
        var win = require(DIR_SERVER + 'win');

        win.getVolumes(function(error, volumes) {
            var data = {
                path    : '/',
                files   : []
            };

            if (!error)
                data.files = volumes.map(function(volume) {
                    return {
                        name: volume,
                        size: 'dir',
                        mode: 0,
                        owner: 0
                    };
                });

            callback(error, data);
        });
    }

    function convertPath(path) {
        var volume;

        Util.checkArgs(arguments, ['path']);

        if (isWin && path !== '/') {
            volume  = path[1];
            path    = path.split('')
                          .slice(2)
                          .join('');

            path    = volume + ':' + path;
        }

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


<commit_before>(function() {
    'use strict';

    var DIR         = '../',
        DIR_SERVER  = DIR + 'server/',

        isWin       = process.platform === 'win32',
        Util        = require(DIR           + 'util'),
        commander   = require(DIR_SERVER    + 'commander');

    exports.read            = read;
    exports.convertPath     = convertPath;

    function read(path, callback) {
        if (isWin && path === '/')
            getRoot(callback);
        else
            commander.getDirContent(path, callback);
    }

    function getRoot(callback) {
        var win = require(DIR_SERVER + 'win');

        win.getVolumes(function(error, volumes) {
            var data = {
                path    : '/',
                files   : []
            };

            if (!error)
                data.files = volumes.map(function(volume) {
                    return {
                        name: volume,
                        size: 'dir',
                        mode: '--- --- ---',
                        owner: 0
                    };
                });

            callback(error, data);
        });
    }

    function convertPath(path) {
        var volume;

        Util.checkArgs(arguments, ['path']);

        if (isWin && path !== '/') {
            volume  = path[1];
            path    = path.split('')
                          .slice(2)
                          .join('');

            path    = volume + ':' + path;
        }

        return path;
    }
})();
<commit_msg>refactor(mellow) getRoot: put win on top<commit_after>(function() {
    'use strict';

    var DIR         = '../',
        DIR_SERVER  = DIR + 'server/',

        isWin       = process.platform === 'win32',
        Util        = require(DIR           + 'util'),

        win         = require(DIR_SERVER    + 'win'),
        commander   = require(DIR_SERVER    + 'commander');

    exports.read            = read;
    exports.convertPath     = convertPath;

    function read(path, callback) {
        if (isWin && path === '/')
            getRoot(callback);
        else
            commander.getDirContent(path, callback);
    }

    function getRoot(callback) {
        win.getVolumes(function(error, volumes) {
            var data = {
                path    : '/',
                files   : []
            };

            if (!error)
                data.files = volumes.map(function(volume) {
                    return {
                        name: volume,
                        size: 'dir',
                        mode: '--- --- ---',
                        owner: 0
                    };
                });

            callback(error, data);
        });
    }

    function convertPath(path) {
        var volume;

        Util.checkArgs(arguments, ['path']);

        if (isWin && path !== '/') {
            volume  = path[1];
            path    = path.split('')
                          .slice(2)
                          .join('');

            path    = volume + ':' + path;
        }

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


<commit_before>/* Module contains Cloud Commander SS(Server Side) objects.
 *
 * List of objects:
 * - Cache
 * - Minify
 */

/*
 * Обьект для работы с кэшем
 * аналог клиентского обьекта
 * с тем отличием, что в нём
 * будут храниться серверные
 * данные, такие как файлы
 * отдаваемые клиенту
 * (файлы проэкта по большому
 * счёту, для ускорения
 * первичной загрузки)
 */
exports.Cache={
    /* приватный переключатель возможности работы с кэшем */
    _allowed            :true,
    /* данные в которых храняться файлы
     * в формате <поле> : <значение>
     * _data[name]=pData;
     * одному имени соответствуют
     * одни данные
     */
    _data               :{},

    /* функция говорит можно ли работать с кэшем */
    isAllowed           :(function(){
        return this._allowed;
        }),
    /* функция устанавливает возможность работать с кэшем */
    setAllowed          :(function(pAllowed){
        this._allowed=pAllowed;
    }),
    /* Если доступен кэш
     * сохраняем в него данные
     */
    set                  :(function(pName, pData){
        if(this._allowed && pName && pData){
            this._data[pName]=pData;
        }
    }),
    /* Если доступен Cache принимаем из него данные*/
    get                 :(function(pName){
        if(this._allowed && pName){
            return this._data[pName];
        }
        else return null;
    }),

    /* Функция очищает кэш*/
    clear               :(function(){
        if(this._allowed){
            this._data={};
        }
    })
};

/* Обьект для сжатия скриптов и стилей
 * по умолчанию - сжимаються
 */
exports.Minify={
    /* pathes to directories */
    INDEX           :'index.html',
    LIBDIR          : './lib/',
    LIBDIRCLIENT    : './lib/client/',
    /* приватный переключатель минимизации */
    _allowed               :{css:true,js:true,html:true, img: true},

    /* функция разрешает или
     * запрещает минимизировать
     * css/js/html
     * @pAllowed: - структура, в которой
     *              передаються параметры
     *              минификации, вида
     *              {js:true,css:true,html:false; img:true}
     * img отвечает за перевод картинок в base64
     * и сохранение их в css-файл
     */
    setAllowed              :(function(pAllowed){
       if(pAllowed){
           this._allowed=pAllowed;
       }
    }),

    /*
     * Функция минимизирует css/js/html
     * если установлены параметры минимизации
     */
    doit                    :(function(){
        if(this._allowed.css ||
            this._allowed.js ||
            this._allowed.html){
                var lMinify;
                try{
                    lMinify      = require('minify');
                }catch(pError){
                    this._allowed={js:false,css:false,html:false};
                    return console.log('Could not minify '  +
                        'withou minify module\n'            +
                        'npm i minify');
                }

                var lOptimizeParams = [];

                if (this._allowed.js) {
                      /*
                 * temporary changed dir path,
                 * becouse directory lib is write
                 * protected by others by default
                 * so if node process is started
                 * from other user (root for example
                 * in nodester) we can not write
                 * minified versions
                 */
                this.MinFolder = '/' + lMinify.MinFolder;
                var lMinFolder=this.MinFolder;

                var getJSFiles_f = function(){
                    return [this.LIBDIR         + 'cloudfunc.js',
                            this.LIBDIRCLIENT   + 'keyBinding.js',
                            this.LIBDIRCLIENT   + 'editor.js',
                            this.LIBDIRCLIENT   + 'viewer.js'];
                };
                var lJSFiles = getJSFiles_f();

                /* post processing function for file
                 * client.js
                 */

                /* если мы сжимаем client.js -
                 * меняем строку cloudfunc.js на
                 * cloudfunc.min.js и выводим сообщение
                 *
                 * меняем строку keyBinding.js на
                 * keyBinding.min.js
                 * если другой файл - ничего не деалем
                 */
                var lPostProcessing_f = function(pFinalCode){
                    console.log('file names in client.js changed:\n');

                    var getMinName_f = function(pName){
                        return pName.replace('.js','min.js');
                    };

                    console.log(lJSFiles);
                    for(var i=0; i < lJSFiles.length; i++){
                        console.log(lJSFiles[i]+'\n');

                        pFinalCode = pFinalCode.replace(lJSFiles[i],
                            getMinName_f(lJSFiles[i]));
                    }

                    pFinalCode = pFinalCode
                        .replace('/lib/client/', lMinFolder)
                            .replace('/lib/', lMinFolder);
                    return pFinalCode;
                };

                    lOptimizeParams = getJSFiles_f();
                    lOptimizeParams[lOptimizeParams.length] = {
                        'client.js': lPostProcessing_f};
                }

                if (this._allowed.html)
                    lOptimizeParams[lOptimizeParams.length] = this.INDEX;

                if (this._allowed.css) {
                    lOptimizeParams[lOptimizeParams.length] = {
                        './css/style.css' : this._allowed.img };

                    lOptimizeParams[lOptimizeParams.length] = {
                        './css/reset.css': this._allowed.img};
                }

                if (lOptimizeParams)
                    lMinify.optimize(lOptimizeParams);

                this.Cache = lMinify.Cache;
        }
    }),

    /* minification folder name */
    MinFolder   :'',
    Cache       :{}
};<commit_msg>minor changes<commit_after>/* Module contains Cloud Commander SS(Server Side) objects.
 *
 * List of objects:
 * - Cache
 * - Minify
 */

/*
 * Обьект для работы с кэшем
 * аналог клиентского обьекта
 * с тем отличием, что в нём
 * будут храниться серверные
 * данные, такие как файлы
 * отдаваемые клиенту
 * (файлы проэкта по большому
 * счёту, для ускорения
 * первичной загрузки)
 */
exports.Cache={
    /* приватный переключатель возможности работы с кэшем */
    _allowed            :true,
    /* данные в которых храняться файлы
     * в формате <поле> : <значение>
     * _data[name]=pData;
     * одному имени соответствуют
     * одни данные
     */
    _data               :{},

    /* функция говорит можно ли работать с кэшем */
    isAllowed           :(function(){
        return this._allowed;
        }),
    /* функция устанавливает возможность работать с кэшем */
    setAllowed          :(function(pAllowed){
        this._allowed=pAllowed;
    }),
    /* Если доступен кэш
     * сохраняем в него данные
     */
    set                  :(function(pName, pData){
        if(this._allowed && pName && pData){
            this._data[pName]=pData;
        }
    }),
    /* Если доступен Cache принимаем из него данные*/
    get                 :(function(pName){
        if(this._allowed && pName){
            return this._data[pName];
        }
        else return null;
    }),

    /* Функция очищает кэш*/
    clear               :(function(){
        if(this._allowed){
            this._data={};
        }
    })
};

/* Обьект для сжатия скриптов и стилей
 * по умолчанию - сжимаються
 */
exports.Minify={
    /* pathes to directories */
    INDEX           :'index.html',
    LIBDIR          : './lib/',
    LIBDIRCLIENT    : './lib/client/',
    /* приватный переключатель минимизации */
    _allowed               :{css:true,js:true,html:true, img: true},

    /* функция разрешает или
     * запрещает минимизировать
     * css/js/html
     * @pAllowed: - структура, в которой
     *              передаються параметры
     *              минификации, вида
     *              {js:true,css:true,html:false; img:true}
     * img отвечает за перевод картинок в base64
     * и сохранение их в css-файл
     */
    setAllowed              :(function(pAllowed){
       if(pAllowed){
           this._allowed=pAllowed;
       }
    }),

    /*
     * Функция минимизирует css/js/html
     * если установлены параметры минимизации
     */
    doit                    :(function(){
        if(this._allowed.css ||
            this._allowed.js ||
            this._allowed.html){
                var lMinify;
                try{
                    lMinify      = require('minify');
                }catch(pError){
                    this._allowed={js:false,css:false,html:false};
                    return console.log('Could not minify '  +
                        'withou minify module\n'            +
                        'npm i minify');
                }

                var lOptimizeParams = [];

                if (this._allowed.js) {
                      /*
                 * temporary changed dir path,
                 * becouse directory lib is write
                 * protected by others by default
                 * so if node process is started
                 * from other user (root for example
                 * in nodester) we can not write
                 * minified versions
                 */
                this.MinFolder = '/' + lMinify.MinFolder;
                var lMinFolder=this.MinFolder;

                var getJSFiles_f = function(){
                    return [this.LIBDIR         + 'cloudfunc.js',
                            this.LIBDIRCLIENT   + 'keyBinding.js',
                            this.LIBDIRCLIENT   + 'editor.js',
                            this.LIBDIRCLIENT   + 'viewer.js'];
                };
                var lJSFiles = getJSFiles_f();

                console.log(lJSFiles);

                /* post processing function for file
                 * client.js
                 */

                /* если мы сжимаем client.js -
                 * меняем строку cloudfunc.js на
                 * cloudfunc.min.js и выводим сообщение
                 *
                 * меняем строку keyBinding.js на
                 * keyBinding.min.js
                 * если другой файл - ничего не деалем
                 */
                var lPostProcessing_f = function(pFinalCode){
                    console.log('file names in client.js changed:\n');

                    var getMinName_f = function(pName){
                        return pName.replace('.js','min.js');
                    };

                    console.log(lJSFiles);
                    for(var i=0; i < lJSFiles.length; i++){
                        console.log(lJSFiles[i]+'\n');

                        pFinalCode = pFinalCode.replace(lJSFiles[i],
                            getMinName_f(lJSFiles[i]));
                    }

                    pFinalCode = pFinalCode
                        .replace('/lib/client/', lMinFolder)
                            .replace('/lib/', lMinFolder);
                    return pFinalCode;
                };

                    lOptimizeParams = getJSFiles_f();
                    lOptimizeParams[lOptimizeParams.length] = {
                        'client.js': lPostProcessing_f};
                }

                if (this._allowed.html)
                    lOptimizeParams[lOptimizeParams.length] = this.INDEX;

                if (this._allowed.css) {
                    lOptimizeParams[lOptimizeParams.length] = {
                        './css/style.css' : this._allowed.img };

                    lOptimizeParams[lOptimizeParams.length] = {
                        './css/reset.css': this._allowed.img};
                }

                if (lOptimizeParams)
                    lMinify.optimize(lOptimizeParams);

                this.Cache = lMinify.Cache;
        }
    }),

    /* minification folder name */
    MinFolder   :'',
    Cache       :{}
};<|endoftext|>