<commit_before>/* -*- js-indent-level:2 -*- */

define(['./sync', './store'], function (sync, store) {
  var moduleChangeHandlers = {};

  function bindContext(callback, context) {
    if(context) {
      return function() { return callback.apply(context, arguments); };
    } else {
      return callback;
    }
  }

  function extractModuleName(path) {
    if (path && typeof(path) == 'string') {
      var parts = path.split('/');
      if(parts.length > 3 && parts[1] == 'public') {
        return parts[2];
      } else if(parts.length > 2){
        return parts[1];
      }
    }
  }

  function fireChange(moduleName, eventObj) {
    if(moduleName && moduleChangeHandlers[moduleName]) {
      for(var i=0; i<moduleChangeHandlers[moduleName].length; i++) {
        moduleChangeHandlers[moduleName][i](eventObj);
      }
    }
  }
  function fireError(str) {
    console.log(str);
  }
  store.on('change', function(e) {
    var moduleName = extractModuleName(e.path);
    fireChange(moduleName, e);//tab-, device- and cloud-based changes all get fired from the store.
    fireChange('root', e);//root module gets everything
  });

  function set(path, absPath, valueStr) {
    if(isDir(absPath)) {
      fireError('attempt to set a value to a directory '+absPath);
      return;
    }
    var  node = store.getNode(absPath);
    var changeEvent = {
      origin: 'window',
      oldValue: node.data,
      newValue: valueStr,
      path: path
    };
    var ret = store.setNodeData(absPath, valueStr, true);
    var moduleName = extractModuleName(absPath);
    fireChange(moduleName, changeEvent);
    fireChange('root', changeEvent);
    return ret;
  }

  function claimAccess(path, claim) {
    store.setNodeAccess(path, claim);
    //sync.syncNow(path);
  }

  function isDir(path) {
    if(typeof(path) != 'string') {
      doSomething();
    }
    return (path.substr(-1)=='/');
  }

  return {
    claimAccess: claimAccess,
    getInstance: function(moduleName, isPublic) {
      function makePath(path) {
        if(moduleName == 'root') {
          return path;
        }
        return (isPublic?'/public/':'/')+moduleName+'/'+path;
      }

      function ensureAccess(mode) {
        var path = makePath('');
        var node = store.getNode(path);
        if(! (new RegExp(mode)).test(node.startAccess)) {
          throw "Not sufficient access claimed for node at " + path + " (need: " + mode + ", have: " + (node.startAccess || 'none') + ")";
        }
      }

      return {

        // helpers for implementations
        h: {
          bindContext: bindContext
        },

        on: function(eventType, cb, context) {//'error' or 'change'. Change events have a path and origin (tab, device, cloud) field
          ensureAccess('r');
          if(eventType=='change') {
            if(moduleName) {
              if(!moduleChangeHandlers[moduleName]) {
                moduleChangeHandlers[moduleName]=[];
              }
              moduleChangeHandlers[moduleName].push(bindContext(cb, context));
            }
          }
        },

        getObject: function(path, cb, context) {
          ensureAccess('r');
          var absPath = makePath(path);
          if(cb) {
            sync.fetchNow(absPath, function(err, node) {
              if(node.data) {
                delete node.data['@type'];
              }
              bindContext(cb, context)(node.data);
            });
          } else {
            var node = store.getNode(absPath);
            if(node.data) {
              delete node.data['@type'];
            }
            return node.data;
          }
        },

        getListing: function(path, cb, context) {
          ensureAccess('r');
          var absPath = makePath(path);
          if(cb) {
            sync.fetchNow(absPath, function(err, node) {
              var arr = [];
              for(var i in node.data) {
                arr.push(i);
              }
              bindContext(cb, context)(arr);
            });
          } else {
            var node = store.getNode(absPath);
            var arr = [];
            for(var i in node.data) {
              arr.push(i);
            }
            return arr;
          }
        },

        getDocument: function(path, cb, context) {
          ensureAccess('r');
          var absPath = makePath(path);
          if(cb) {
            sync.fetchNow(absPath, function(err, node) {
              bindContext(cb, context)({
                mimeType: node.mimeType,
                data: node.data
              });
            });
          } else {
            var node = store.getNode(absPath);
            return {
              mimeType: node.mimeType,
              data: node.data
            };
          }
        },

        remove: function(path) {
          ensureAccess('w');
          var ret = set(path, makePath(path));
          //sync.syncNow('/', function(errors) {
          //});
          return ret;
        },

        storeObject: function(type, path, obj) {
          ensureAccess('w');
          obj['@type'] = 'https://remotestoragejs.com/spec/modules/'+moduleName+'/'+type;
          //checkFields(obj);
          var ret = set(path, makePath(path), obj, 'application/json');
          //sync.syncNow('/', function(errors) {
          //});
          return ret;
        },

        storeDocument: function(mimeType, path, data) {
          ensureAccess('w');
          var ret = set(path, makePath(path), data, mimeType);
          //sync.syncNow('/', function(errors) {
          //});
          return ret;
        },

        /**
           Get the full URL of the item at given path.
           This will only work, if the user is connected to a remoteStorage account,
           otherwise it returns null.
        */
        getItemURL: function(path) {
          var base = remoteStorage.getStorageHref();
          if(! base) {
            return null;
          }
          if(base.substr(-1) != '/') {
            base = base + '/';
          }
          return base + makePath(path);
        },

        getCurrentWebRoot: function() {
          return 'https://example.com/this/is/an/example/'+(isPublic?'public/':'')+moduleName+'/';
        },

        sync: function(path, switchVal) {
          var absPath = makePath(path);
          store.setNodeForce(absPath, (switchVal != false));
        },

        getState: function(path) {
        }
      };
    }
  };
});
<commit_msg>don't require access to be claimed for baseClient.on()<commit_after>/* -*- js-indent-level:2 -*- */

define(['./sync', './store'], function (sync, store) {
  var moduleChangeHandlers = {};

  function bindContext(callback, context) {
    if(context) {
      return function() { return callback.apply(context, arguments); };
    } else {
      return callback;
    }
  }

  function extractModuleName(path) {
    if (path && typeof(path) == 'string') {
      var parts = path.split('/');
      if(parts.length > 3 && parts[1] == 'public') {
        return parts[2];
      } else if(parts.length > 2){
        return parts[1];
      }
    }
  }

  function fireChange(moduleName, eventObj) {
    if(moduleName && moduleChangeHandlers[moduleName]) {
      for(var i=0; i<moduleChangeHandlers[moduleName].length; i++) {
        moduleChangeHandlers[moduleName][i](eventObj);
      }
    }
  }
  function fireError(str) {
    console.log(str);
  }
  store.on('change', function(e) {
    var moduleName = extractModuleName(e.path);
    fireChange(moduleName, e);//tab-, device- and cloud-based changes all get fired from the store.
    fireChange('root', e);//root module gets everything
  });

  function set(path, absPath, valueStr) {
    if(isDir(absPath)) {
      fireError('attempt to set a value to a directory '+absPath);
      return;
    }
    var  node = store.getNode(absPath);
    var changeEvent = {
      origin: 'window',
      oldValue: node.data,
      newValue: valueStr,
      path: path
    };
    var ret = store.setNodeData(absPath, valueStr, true);
    var moduleName = extractModuleName(absPath);
    fireChange(moduleName, changeEvent);
    fireChange('root', changeEvent);
    return ret;
  }

  function claimAccess(path, claim) {
    store.setNodeAccess(path, claim);
    //sync.syncNow(path);
  }

  function isDir(path) {
    if(typeof(path) != 'string') {
      doSomething();
    }
    return (path.substr(-1)=='/');
  }

  return {
    claimAccess: claimAccess,
    getInstance: function(moduleName, isPublic) {
      function makePath(path) {
        if(moduleName == 'root') {
          return path;
        }
        return (isPublic?'/public/':'/')+moduleName+'/'+path;
      }

      function ensureAccess(mode) {
        var path = makePath('');
        var node = store.getNode(path);
        if(! (new RegExp(mode)).test(node.startAccess)) {
          throw "Not sufficient access claimed for node at " + path + " (need: " + mode + ", have: " + (node.startAccess || 'none') + ")";
        }
      }

      return {

        // helpers for implementations
        h: {
          bindContext: bindContext
        },

        on: function(eventType, cb, context) {//'error' or 'change'. Change events have a path and origin (tab, device, cloud) field
          if(eventType=='change') {
            if(moduleName) {
              if(!moduleChangeHandlers[moduleName]) {
                moduleChangeHandlers[moduleName]=[];
              }
              moduleChangeHandlers[moduleName].push(bindContext(cb, context));
            }
          }
        },

        getObject: function(path, cb, context) {
          ensureAccess('r');
          var absPath = makePath(path);
          if(cb) {
            sync.fetchNow(absPath, function(err, node) {
              if(node.data) {
                delete node.data['@type'];
              }
              bindContext(cb, context)(node.data);
            });
          } else {
            var node = store.getNode(absPath);
            if(node.data) {
              delete node.data['@type'];
            }
            return node.data;
          }
        },

        getListing: function(path, cb, context) {
          ensureAccess('r');
          var absPath = makePath(path);
          if(cb) {
            sync.fetchNow(absPath, function(err, node) {
              var arr = [];
              for(var i in node.data) {
                arr.push(i);
              }
              bindContext(cb, context)(arr);
            });
          } else {
            var node = store.getNode(absPath);
            var arr = [];
            for(var i in node.data) {
              arr.push(i);
            }
            return arr;
          }
        },

        getDocument: function(path, cb, context) {
          ensureAccess('r');
          var absPath = makePath(path);
          if(cb) {
            sync.fetchNow(absPath, function(err, node) {
              bindContext(cb, context)({
                mimeType: node.mimeType,
                data: node.data
              });
            });
          } else {
            var node = store.getNode(absPath);
            return {
              mimeType: node.mimeType,
              data: node.data
            };
          }
        },

        remove: function(path) {
          ensureAccess('w');
          var ret = set(path, makePath(path));
          //sync.syncNow('/', function(errors) {
          //});
          return ret;
        },

        storeObject: function(type, path, obj) {
          ensureAccess('w');
          obj['@type'] = 'https://remotestoragejs.com/spec/modules/'+moduleName+'/'+type;
          //checkFields(obj);
          var ret = set(path, makePath(path), obj, 'application/json');
          //sync.syncNow('/', function(errors) {
          //});
          return ret;
        },

        storeDocument: function(mimeType, path, data) {
          ensureAccess('w');
          var ret = set(path, makePath(path), data, mimeType);
          //sync.syncNow('/', function(errors) {
          //});
          return ret;
        },

        /**
           Get the full URL of the item at given path.
           This will only work, if the user is connected to a remoteStorage account,
           otherwise it returns null.
        */
        getItemURL: function(path) {
          var base = remoteStorage.getStorageHref();
          if(! base) {
            return null;
          }
          if(base.substr(-1) != '/') {
            base = base + '/';
          }
          return base + makePath(path);
        },

        getCurrentWebRoot: function() {
          return 'https://example.com/this/is/an/example/'+(isPublic?'public/':'')+moduleName+'/';
        },

        sync: function(path, switchVal) {
          var absPath = makePath(path);
          store.setNodeForce(absPath, (switchVal != false));
        },

        getState: function(path) {
        }
      };
    }
  };
});
<|endoftext|>


<commit_before>var debug = true;

// REF: http://stackoverflow.com/questions/281264/remove-empty-elements-from-an-array-in-javascript
Array.prototype.clean = function(deleteValue) {
    for (var i = 0; i < this.length; i++) {
        if (this[i] == deleteValue) {
        this.splice(i, 1);
        i--;
        }
    }
    return this;
};

// Wrap the console.log function under debug flag
function log(msg) {
    if (debug) {console.log(msg)};
}

// This function will decode a HEX string into ASCII
function hex2a(hex) {
    var str = '';
    for (var i = 0; i < hex.length; i += 2) str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
    return str;
}

// Grab data from localStorage
var storagePrefix = "F5ApmExtensionSettings_";
var defSettings = {
    // Enable debug header on requests for a given domain
    enableDebug: false,
    enableDebugStrict: false,
    debugHeaderName: "DEBUG_F5",
    debugHeaderValue: "1",
    debugDomains: "",

    // Add Session Report Link
    enableSessionLink: false,
    mgmtUrl: "",

    // Enable the extension on a given header value for the Server header
    enableOnHeaderServer: false,
    onHeaderServerValue: "Bigip"
}
function LoadSetting(name) {
    return (localStorage[storagePrefix + name] || defSettings[name]);
}
function SetSetting(name, value) {
    localStorage[storagePrefix + name] = value;
}

<commit_msg>updates<commit_after>var debug = true;

// REF: http://stackoverflow.com/questions/281264/remove-empty-elements-from-an-array-in-javascript
Array.prototype.clean = function(deleteValue) {
    for (var i = 0; i < this.length; i++) {
        if (this[i] == deleteValue) {
            this.splice(i, 1);
            i--;
        }
    }
    return this;
};

// Wrap the console.log function under debug flag
function log(msg) {
    if (debug) {console.log(msg)};
}

// This function will decode a HEX string into ASCII
function hex2a(hex) {
    var str = '';
    for (var i = 0; i < hex.length; i += 2) str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
    return str;
}

// Grab data from localStorage
var storagePrefix = "F5ApmExtensionSettings_";
var defSettings = {
    // Enable debug header on requests for a given domain
    enableDebug: false,
    enableDebugStrict: false,
    debugHeaderName: "DEBUG_F5",
    debugHeaderValue: "1",
    debugDomains: "",

    // Add Session Report Link
    enableSessionLink: false,
    mgmtUrl: "",

    // Enable the extension on a given header value for the Server header
    enableOnHeaderServer: false,
    onHeaderServerValue: "Bigip"
}
function LoadSetting(name) {
    return (localStorage[storagePrefix + name] || defSettings[name]);
}
function SetSetting(name, value) {
    localStorage[storagePrefix + name] = value;
}

<|endoftext|>


<commit_before>import React from 'react';
import * as d3 from 'd3';
import _ from 'lodash';

import {
  STATUS_NONE,
  STATUS_SUCCESS,
  STATUS_ERROR,
} from '../../../watcher/models/watch_result';

const STATUS_TO_COLOR_MAP = {};
STATUS_TO_COLOR_MAP[STATUS_NONE] = '#111111';
STATUS_TO_COLOR_MAP[STATUS_SUCCESS] = '#00de0e';
STATUS_TO_COLOR_MAP[STATUS_ERROR] = '#ff3800';

function ComponentNode(props) {
  const { component, d3Node } = props;
  const status = component.watchers[0].result.status;
  return (
    <g>
      <circle
        cx={d3Node.x}
        cy={d3Node.y}
        r={d3Node.size / 2}
        fill={STATUS_TO_COLOR_MAP[status]}
      />
      <text
        textAnchor="middle"
        x={d3Node.x}
        y={d3Node.y - d3Node.size / 2 - 5}
      >
        {component.name}
      </text>
    </g>
  );
}

ComponentNode.propTypes = {
  component: React.PropTypes.object,
  d3Node: React.PropTypes.object,
};

class ComponentsGraph extends React.Component {
  constructor(props) {
    super(props);

    const svgWidth = 900;
    const svgHeight = 400;

    this.state = {
      svgWidth,
      svgHeight,
      nodes: null,
      links: null,
      d3Nodefs: {},
    };
  }

  componentDidMount() {
    this.initD3Nodes(this.props.components);
  }

  componentWillReceiveProps(nextProps) {
    this.initD3Nodes(nextProps.components);
  }

  initD3Nodes(components) {
    const { d3Nodes } = this.state;
    const originalSize = _.values(d3Nodes).length;
    components.forEach((c) => {
      let d3Node = d3Nodes[c.id];
      if (!d3Node) {
        d3Node = {
          index: c.id,
          x: 0,
          y: 0,
          size: 50,
        };
      }
      d3Nodes[c.id] = d3Node;
    });

    if (_.values(d3Nodes).length !== originalSize) {
      const { svgWidth, svgHeight } = this.state;

      const forceManyBody = d3.forceManyBody();
      forceManyBody.strength(-10);

      const forceCenter = d3.forceCenter();
      forceCenter.x(svgWidth / 2);
      forceCenter.y(svgHeight / 2);

      const force =
        d3.forceSimulation(_.values(d3Nodes))
          .force('charge', forceManyBody)
          .force('center', forceCenter);

      force.on('tick', () => {
        this.eachD3Nodes((node) => {
          Object.assign({
            x: Math.max(node.size, Math.min(this.state.svgWidth - node.size, node.x)),
            y: Math.max(node.size, Math.min(this.state.svgHeight - node.size, node.y)),
          }, node);
        });

        this.forceUpdate();
      });
    }
  }

  eachD3Nodes(loop) {
    this.props.components.forEach((component, index) => {
      const node = this.state.d3Nodes[component.id];
      if (node && component) {
        loop(node, component, index);
      }
    });
  }

  drawLinks() {
  }

  drawNodes() {
    const nodes = [];

    this.eachD3Nodes((node, component, index) => {
      if (node && component && component.watchers.length > 0) {
        nodes.push(
          <ComponentNode
            key={index}
            component={component}
            d3Node={node}
          />
        );
      }
    });

    return nodes;
  }

  render() {
    return (

        <svg
          width={this.state.svgWidth}
          height={this.state.svgHeight}
        >
          {this.drawLinks()}
          {this.drawNodes()}
        </svg>

    );
  }
}
ComponentsGraph.propTypes = {
  components: React.PropTypes.array,
};

export default ComponentsGraph;
<commit_msg>fix typo<commit_after>import React from 'react';
import * as d3 from 'd3';
import _ from 'lodash';

import {
  STATUS_NONE,
  STATUS_SUCCESS,
  STATUS_ERROR,
} from '../../../watcher/models/watch_result';

const STATUS_TO_COLOR_MAP = {};
STATUS_TO_COLOR_MAP[STATUS_NONE] = '#111111';
STATUS_TO_COLOR_MAP[STATUS_SUCCESS] = '#00de0e';
STATUS_TO_COLOR_MAP[STATUS_ERROR] = '#ff3800';

function ComponentNode(props) {
  const { component, d3Node } = props;
  const status = component.watchers[0].result.status;
  return (
    <g>
      <circle
        cx={d3Node.x}
        cy={d3Node.y}
        r={d3Node.size / 2}
        fill={STATUS_TO_COLOR_MAP[status]}
      />
      <text
        textAnchor="middle"
        x={d3Node.x}
        y={d3Node.y - d3Node.size / 2 - 5}
      >
        {component.name}
      </text>
    </g>
  );
}

ComponentNode.propTypes = {
  component: React.PropTypes.object,
  d3Node: React.PropTypes.object,
};

class ComponentsGraph extends React.Component {
  constructor(props) {
    super(props);

    const svgWidth = 900;
    const svgHeight = 400;

    this.state = {
      svgWidth,
      svgHeight,
      nodes: null,
      links: null,
      d3Nodes: {},
    };
  }

  componentDidMount() {
    this.initD3Nodes(this.props.components);
  }

  componentWillReceiveProps(nextProps) {
    this.initD3Nodes(nextProps.components);
  }

  initD3Nodes(components) {
    const { d3Nodes } = this.state;
    const originalSize = _.values(d3Nodes).length;
    components.forEach((c) => {
      let d3Node = d3Nodes[c.id];
      if (!d3Node) {
        d3Node = {
          index: c.id,
          x: 0,
          y: 0,
          size: 50,
        };
      }
      d3Nodes[c.id] = d3Node;
    });

    if (_.values(d3Nodes).length !== originalSize) {
      const { svgWidth, svgHeight } = this.state;

      const forceManyBody = d3.forceManyBody();
      forceManyBody.strength(-10);

      const forceCenter = d3.forceCenter();
      forceCenter.x(svgWidth / 2);
      forceCenter.y(svgHeight / 2);

      const force =
        d3.forceSimulation(_.values(d3Nodes))
          .force('charge', forceManyBody)
          .force('center', forceCenter);

      force.on('tick', () => {
        this.eachD3Nodes((node) => {
          Object.assign({
            x: Math.max(node.size, Math.min(this.state.svgWidth - node.size, node.x)),
            y: Math.max(node.size, Math.min(this.state.svgHeight - node.size, node.y)),
          }, node);
        });

        this.forceUpdate();
      });
    }
  }

  eachD3Nodes(loop) {
    this.props.components.forEach((component, index) => {
      const node = this.state.d3Nodes[component.id];
      if (node && component) {
        loop(node, component, index);
      }
    });
  }

  drawLinks() {
  }

  drawNodes() {
    const nodes = [];

    this.eachD3Nodes((node, component, index) => {
      if (node && component && component.watchers.length > 0) {
        nodes.push(
          <ComponentNode
            key={index}
            component={component}
            d3Node={node}
          />
        );
      }
    });

    return nodes;
  }

  render() {
    return (

        <svg
          width={this.state.svgWidth}
          height={this.state.svgHeight}
        >
          {this.drawLinks()}
          {this.drawNodes()}
        </svg>

    );
  }
}
ComponentsGraph.propTypes = {
  components: React.PropTypes.array,
};

export default ComponentsGraph;
<|endoftext|>


<commit_before>/*jshint bitwise: true, camelcase: true, curly: true, eqeqeq: true, forin: true, immed: true, indent: 4, latedef: true, newcap: true, noarg: true, noempty: true, nonew: true, regexp: true, undef: true, unused: true, strict: true*/
/*global define*/
define(["util"], function (util) {

    "use strict";

    function error(msg, expr) {
        // TODO: add line/char details to forms for better errors
        throw new Error(msg + " @ " + util.printPretty(expr));
    }

    /**
     * Checks whether `expr` is a valid non-object-property id.
     */
    function isStandardId(expr) {
        return expr.type === "symbol" && expr.value.charAt(0) !== ".";
    }

    /**
     * Checks whether `expr` is a valid object property - an expression of the
     * form `(.name expr)` where `.name` is any symbol starting with `.` and
     * `expr` is any valid expression.
     */
    function isProp(expr) {
        if (expr.type === "list" && expr.value.length === 2) {
            var prop = expr.value[0];
            if (prop.type === "symbol" && prop.value.charAt(0) === ".") {
                return true;
            }
        }
        return false;
    }

    /**
     * Checks whether `atoms` are valid values for an application of the
     * primitive `import`. The valid form for `import` is `(import name ...)`
     * where `name ...` is a list of non-empty string literals. The full version
     * of the form being checked is provided as `expr` for use in error
     * messages.
     */
    function checkImport(atoms, expr) {
        if (atoms.length === 0) {
            error("import: bad syntax - empty expression", expr);
        }
        for (var i = 0, l = atoms.length; i < l; i++) {
            var name = atoms[i];
            if (name.type !== "literal" || (typeof name.value !== "string")) {
                error("import: invalid import name, should be a string", name);
            }
            if (name.value.length === 0) {
                error("import: invalid import name, empty string", name);
            }
        }
    }

    /**
     * Checks whether `atoms` are valid values for an application of the
     * primitive `var`. The valid form for `var` is `(var id value)` where `id`
     * is any symbol not starting with `.`, and `value` is any valid
     * expression. The full version of the form being checked is provided as
     * `expr` for use in error messages.
     */
    function checkVar(atoms, expr) {
        if (atoms.length === 0) {
            error("var: bad syntax - empty expression", expr);
        }
        if (atoms.length === 1) {
            error("var: no value specified", expr);
        }
        if (atoms.length > 2) {
            error("var: expects 2 arguments", expr);
        }
        if (!isStandardId(atoms[0])) {
            error("var: invalid identifier", atoms[0]);
        }
    }

    /**
     * Checks whether `atoms` are valid values for an application of the
     * primitive `fn`. The valid form for `fn` is `(fn (args ...) body ...)` or
     * `(fn rest body ...)` where `args ...` is a list of symbols not starting
     * with `.`, `rest` is a symbol not starting with `.` and `body ...` is a
     * list of any valid expressions. The full version of the form being checked
     * is provided as `expr` for use  in error messages.
     */
    function checkFunction(atoms, expr) {
        if (atoms.length === 0) {
            error("fn: empty expression", expr);
        }
        if (atoms.length === 1) {
            error("fn: no body specified", expr);
        }
        var args = atoms[0];
        if (args.type === "list") {
            for (var i = 0, l = args.value.length; i < l; i++) {
                var arg = args.value[i];
                if (!isStandardId(arg)) {
                    error("fn: invalid argument identifier", arg);
                }
            }
        } else if (!isStandardId(args)) {
            error("fn: invalid argument identifier", args);
        }
    }

    /**
     * Checks whether `atoms` are valid values for an application of the
     * primitive `set!`. The valid form for `set!` is `(set! assignee value)`
     * where `assignee` is an object property or a symbol not starting with `.`,
     * and `value` is any valid expressions. The full version of the form being
     * checked is provided as `expr` for use  in error messages.
     */
    function checkAssign(atoms, expr) {
        if (atoms.length === 0) {
            error("set!: empty expression", expr);
        }
        if (atoms.length === 1) {
            error("set!: no value specified", expr);
        }
        if (atoms.length > 2) {
            error("set!: too many arguments", expr);
        }
        if (!isStandardId(atoms[0]) && !isProp(atoms[0])) {
            error("set!: invalid assignee", atoms[0]);
        }
    }

    /**
     * Checks whether `atoms` are valid values for an application of the
     * primitive `if`. The valid form for `if` is `(if test then else)`
     * where `test`, `then`, and `else` are valid expressions. The full version
     * of the form being checked is provided as `expr` for use in error
     * messages.
     */
    function checkIf(atoms, expr) {
        if (atoms.length === 0) {
            error("if: empty expression", expr);
        }
        if (atoms.length === 1) {
            error("if: no then and else clauses", expr);
        }
        if (atoms.length === 2) {
            error("if: no else clause", expr);
        }
    }

    /**
     * Checks whether `atoms` are valid values for an application of the
     * primitive `quote`. The valid form for `if` is `(quote datum)`
     * where `datum` is any s-expression. The full version of the form being
     * checked is provided as `expr` for use in error messages.
     */
    function checkQuote(atoms, expr) {
        if (atoms.length === 0) {
            error("quote: empty expression", expr);
        }
        if (atoms.length > 1) {
            error("quote: too many arguments", expr);
        }
    }

    /**
     * Checks whether `atoms` are valid values for an application of the
     * primitive `quasiquote`. The valid form for `quasiquote` is
     * `(quasiquote datum)` where `datum` is any s-expression. The syntax of any
     * `unquote` or `unquote-splicing` forms within datum are also checked,
     * although the unquoted expressions are not. The full version of the form
     * being checked is provided as `expr` for use in error messages.
     */
    function checkQuasiQuote(atoms, expr) {
        if (atoms.length === 0) {
            error("quasiquote: empty expression", expr);
        }
        if (atoms.length > 1) {
            error("quasiquote: too many arguments", expr);
        }
        checkQuasiQuoteValue(atoms[0]);
    }

    /**
     * Checks `datum` for uses of `unquote` and `unquote-splicing` to ensure
     * they are of the correct form - `(unquote expr)` or
     * `(unquote-splicing expr)` where `expr` is any valid expression.
     */
    function checkQuasiQuoteValue(datum) {
        if (datum.type === "list" && datum.value.length > 0) {
            var car = datum.value[0];
            if (car.type === "symbol") {
                if (car.value === "unquote") {
                    if (datum.value.length === 1) {
                        error("unquote: empty expression", datum);
                    }
                    if (datum.value.length > 2) {
                        error("unquote: too many arguments", datum);
                    }
                } else if (car.value === "unquote-splicing") {
                    error("unquote-splicing: not in list", datum);
                }
            }
            for (var i = 0, l = datum.value.length; i < l; i++) {
                var f = datum.value[i];
                if (util.checkForm(f, "unquote-splicing")) {
                    if (f.value.length === 1) {
                        error("unquote-splicing: empty expression", f);
                    }
                    if (f.value.length > 2) {
                        error("unquote-splicing: too many arguments", f);
                    }
                } else {
                    checkQuasiQuoteValue(datum.value[i]);
                }
            }
        }
    }

    /**
     * Rasises an error for primitive form of `type` because it should only
     * appear inside a quasiquote.
     */
    function quasiQuoteError(type) {
        return function () {
            error(type + ": not in quasiquote", arguments[1]);
        };
    }

    /**
     * Checks whether `atoms` are valid values for an application of the
     * primitive `define-syntax`. The valid form for `define-syntax` is
     * `(define-syntax id transformer)` where `id` is a symbol and transformer
     * is a `syntax-rules` expression. The full version of the form
     * being checked is provided as `expr` for use in error messages.
     */
    function checkDefineSyntax(atoms, expr) {
        if (atoms.length === 0) {
            error("define-syntax: empty expression", expr);
        }
        if (atoms.length === 1) {
            error("define-syntax: missing transformer definition", expr);
        }
        if (atoms.length > 2) {
            error("define-syntax: too many arguments", expr);
        }
        if (!util.checkForm(atoms[1], "syntax-rules")) {
            error("define-syntax: transformer should be a `syntax-rules` form");
        }
    }

    function checkSyntaxTransformer(atoms, expr) {
        if (atoms.length === 0) {
            error("syntax-rules: empty expression", expr);
        }
        if (atoms.length === 1) {
            error("syntax-rules: missing pattern and template definitions", expr);
        }
        if (atoms.length > 2) {
            error("syntax-rules: too many arguments", expr);
        }
        var symbols = atoms[0];
        if (symbols.type !== "list") {
            error("syntax-rules: invalid reserved symbol list", symbols);
            for (var i = 0, l = symbols.value.length; i < l; i++) {
                if (symbols.value[i].type !== "symbol") {
                    error("syntax-rules: invalid reserved symbol", symbols.value[i]);
                }
            }
        }
        // TODO: check pattern/template list conforms
    }

    return {
        checks: {
            "import": checkImport,
            "var": checkVar,
            "fn": checkFunction,
            "set!": checkAssign,
            "if": checkIf,
            "quote": checkQuote,
            "quasiquote": checkQuasiQuote,
            "unquote": quasiQuoteError("unquote"),
            "unquote-splicing": quasiQuoteError("unquote-splicing"),
            "define-syntax": checkDefineSyntax,
            "syntax-rules": checkSyntaxTransformer
        }
    };
});<commit_msg>Enhanced syntax checking for syntax-rules<commit_after>/*jshint bitwise: true, camelcase: true, curly: true, eqeqeq: true, forin: true, immed: true, indent: 4, latedef: true, newcap: true, noarg: true, noempty: true, nonew: true, regexp: true, undef: true, unused: true, strict: true*/
/*global define*/
define(["util"], function (util) {

    "use strict";

    function error(msg, expr) {
        // TODO: add line/char details to forms for better errors
        throw new Error(msg + " @ " + util.printPretty(expr));
    }

    /**
     * Checks whether `expr` is a valid non-object-property id.
     */
    function isStandardId(expr) {
        return expr.type === "symbol" && expr.value.charAt(0) !== ".";
    }

    /**
     * Checks whether `expr` is a valid object property - an expression of the
     * form `(.name expr)` where `.name` is any symbol starting with `.` and
     * `expr` is any valid expression.
     */
    function isProp(expr) {
        if (expr.type === "list" && expr.value.length === 2) {
            var prop = expr.value[0];
            if (prop.type === "symbol" && prop.value.charAt(0) === ".") {
                return true;
            }
        }
        return false;
    }

    /**
     * Checks whether `atoms` are valid values for an application of the
     * primitive `import`. The valid form for `import` is `(import name ...)`
     * where `name ...` is a list of non-empty string literals. The full version
     * of the form being checked is provided as `expr` for use in error
     * messages.
     */
    function checkImport(atoms, expr) {
        if (atoms.length === 0) {
            error("import: bad syntax - empty expression", expr);
        }
        for (var i = 0, l = atoms.length; i < l; i++) {
            var name = atoms[i];
            if (name.type !== "literal" || (typeof name.value !== "string")) {
                error("import: invalid import name, should be a string", name);
            }
            if (name.value.length === 0) {
                error("import: invalid import name, empty string", name);
            }
        }
    }

    /**
     * Checks whether `atoms` are valid values for an application of the
     * primitive `var`. The valid form for `var` is `(var id value)` where `id`
     * is any symbol not starting with `.`, and `value` is any valid
     * expression. The full version of the form being checked is provided as
     * `expr` for use in error messages.
     */
    function checkVar(atoms, expr) {
        if (atoms.length === 0) {
            error("var: bad syntax - empty expression", expr);
        }
        if (atoms.length === 1) {
            error("var: no value specified", expr);
        }
        if (atoms.length > 2) {
            error("var: expects 2 arguments", expr);
        }
        if (!isStandardId(atoms[0])) {
            error("var: invalid identifier", atoms[0]);
        }
    }

    /**
     * Checks whether `atoms` are valid values for an application of the
     * primitive `fn`. The valid form for `fn` is `(fn (args ...) body ...)` or
     * `(fn rest body ...)` where `args ...` is a list of symbols not starting
     * with `.`, `rest` is a symbol not starting with `.` and `body ...` is a
     * list of any valid expressions. The full version of the form being checked
     * is provided as `expr` for use  in error messages.
     */
    function checkFunction(atoms, expr) {
        if (atoms.length === 0) {
            error("fn: empty expression", expr);
        }
        if (atoms.length === 1) {
            error("fn: no body specified", expr);
        }
        var args = atoms[0];
        if (args.type === "list") {
            for (var i = 0, l = args.value.length; i < l; i++) {
                var arg = args.value[i];
                if (!isStandardId(arg)) {
                    error("fn: invalid argument identifier", arg);
                }
            }
        } else if (!isStandardId(args)) {
            error("fn: invalid argument identifier", args);
        }
    }

    /**
     * Checks whether `atoms` are valid values for an application of the
     * primitive `set!`. The valid form for `set!` is `(set! assignee value)`
     * where `assignee` is an object property or a symbol not starting with `.`,
     * and `value` is any valid expressions. The full version of the form being
     * checked is provided as `expr` for use  in error messages.
     */
    function checkAssign(atoms, expr) {
        if (atoms.length === 0) {
            error("set!: empty expression", expr);
        }
        if (atoms.length === 1) {
            error("set!: no value specified", expr);
        }
        if (atoms.length > 2) {
            error("set!: too many arguments", expr);
        }
        if (!isStandardId(atoms[0]) && !isProp(atoms[0])) {
            error("set!: invalid assignee", atoms[0]);
        }
    }

    /**
     * Checks whether `atoms` are valid values for an application of the
     * primitive `if`. The valid form for `if` is `(if test then else)`
     * where `test`, `then`, and `else` are valid expressions. The full version
     * of the form being checked is provided as `expr` for use in error
     * messages.
     */
    function checkIf(atoms, expr) {
        if (atoms.length === 0) {
            error("if: empty expression", expr);
        }
        if (atoms.length === 1) {
            error("if: no then and else clauses", expr);
        }
        if (atoms.length === 2) {
            error("if: no else clause", expr);
        }
    }

    /**
     * Checks whether `atoms` are valid values for an application of the
     * primitive `quote`. The valid form for `if` is `(quote datum)`
     * where `datum` is any s-expression. The full version of the form being
     * checked is provided as `expr` for use in error messages.
     */
    function checkQuote(atoms, expr) {
        if (atoms.length === 0) {
            error("quote: empty expression", expr);
        }
        if (atoms.length > 1) {
            error("quote: too many arguments", expr);
        }
    }

    /**
     * Checks whether `atoms` are valid values for an application of the
     * primitive `quasiquote`. The valid form for `quasiquote` is
     * `(quasiquote datum)` where `datum` is any s-expression. The syntax of any
     * `unquote` or `unquote-splicing` forms within datum are also checked,
     * although the unquoted expressions are not. The full version of the form
     * being checked is provided as `expr` for use in error messages.
     */
    function checkQuasiQuote(atoms, expr) {
        if (atoms.length === 0) {
            error("quasiquote: empty expression", expr);
        }
        if (atoms.length > 1) {
            error("quasiquote: too many arguments", expr);
        }
        checkQuasiQuoteValue(atoms[0]);
    }

    /**
     * Checks `datum` for uses of `unquote` and `unquote-splicing` to ensure
     * they are of the correct form - `(unquote expr)` or
     * `(unquote-splicing expr)` where `expr` is any valid expression.
     */
    function checkQuasiQuoteValue(datum) {
        if (datum.type === "list" && datum.value.length > 0) {
            var car = datum.value[0];
            if (car.type === "symbol") {
                if (car.value === "unquote") {
                    if (datum.value.length === 1) {
                        error("unquote: empty expression", datum);
                    }
                    if (datum.value.length > 2) {
                        error("unquote: too many arguments", datum);
                    }
                } else if (car.value === "unquote-splicing") {
                    error("unquote-splicing: not in list", datum);
                }
            }
            for (var i = 0, l = datum.value.length; i < l; i++) {
                var f = datum.value[i];
                if (util.checkForm(f, "unquote-splicing")) {
                    if (f.value.length === 1) {
                        error("unquote-splicing: empty expression", f);
                    }
                    if (f.value.length > 2) {
                        error("unquote-splicing: too many arguments", f);
                    }
                } else {
                    checkQuasiQuoteValue(datum.value[i]);
                }
            }
        }
    }

    /**
     * Rasises an error for primitive form of `type` because it should only
     * appear inside a quasiquote.
     */
    function quasiQuoteError(type) {
        return function () {
            error(type + ": not in quasiquote", arguments[1]);
        };
    }

    /**
     * Checks whether `atoms` are valid values for an application of the
     * primitive `define-syntax`. The valid form for `define-syntax` is
     * `(define-syntax id transformer)` where `id` is a symbol and transformer
     * is a `syntax-rules` expression. The full version of the form
     * being checked is provided as `expr` for use in error messages.
     */
    function checkDefineSyntax(atoms, expr) {
        if (atoms.length === 0) {
            error("define-syntax: empty expression", expr);
        }
        if (atoms.length === 1) {
            error("define-syntax: missing transformer definition", expr);
        }
        if (atoms.length > 2) {
            error("define-syntax: too many arguments", expr);
        }
        if (!util.checkForm(atoms[1], "syntax-rules")) {
            error("define-syntax: transformer should be a `syntax-rules` form");
        }
    }

    /**
     * Checks whether `atoms` are valid values for an application of the
     * primitive `syntax-rules`. The valid form for `syntax-rules` is
     * `(syntax-rules (reserved ...) ((pattern template) ...)` where
     * `reserved ...` is a list of symbols, `pattern` is a list starting with a
     * symbol, and `template` is any s-expression. The full version of the form
     * being checked is provided as `expr` for use in error messages.
     */
    function checkSyntaxRules(atoms, expr) {
        if (atoms.length === 0) {
            error("syntax-rules: empty expression", expr);
        }
        if (atoms.length === 1) {
            error("syntax-rules: missing pattern and template definitions", expr);
        }
        if (atoms.length > 2) {
            error("syntax-rules: too many arguments", expr);
        }
        var symbols = atoms[0];
        if (symbols.type !== "list") {
            error("syntax-rules: invalid reserved symbol list", symbols);
            for (var i = 0, l = symbols.value.length; i < l; i++) {
                if (symbols.value[i].type !== "symbol") {
                    error("syntax-rules: invalid reserved symbol", symbols.value[i]);
                }
            }
        }
        var rules = atoms[1];
        if (rules.type !== "list") {
            error("syntax-rules: rules should be a list", rules);
        }
        if (rules.value.length === 0) {
            error("syntax-rules: empty rules list", rules);
        }
        for (var j = 0, m = rules.value.length; j < m; j++) {
            var rule = rules.value[j];
            if (rule.type !== "list") {
                error("syntax-rules: invalid rule", rule);
            }
            if (rule.value.length === 0) {
                error("syntax-rules: empty rule", rule);
            }
            if (rule.value.length === 1) {
                error("syntax-rules: rule missing template definition", rule);
            }
            if (rule.value.length > 2) {
                error("syntax-rules: rule has too many arguments", rule);
            }
            if (rule.value[0].type !== "list") {
                error("syntax-rules: pattern should be a list expression", rule);
            }
            if (rule.value[0].value[0].type !== "symbol") {
                error("syntax-rules: pattern should start with an identifier", rule);
            }
        }
    }

    return {
        checks: {
            "import": checkImport,
            "var": checkVar,
            "fn": checkFunction,
            "set!": checkAssign,
            "if": checkIf,
            "quote": checkQuote,
            "quasiquote": checkQuasiQuote,
            "unquote": quasiQuoteError("unquote"),
            "unquote-splicing": quasiQuoteError("unquote-splicing"),
            "define-syntax": checkDefineSyntax,
            "syntax-rules": checkSyntaxRules
        }
    };
});<|endoftext|>


<commit_before>var Component = new Brick.Component();
Component.requires = {
    mod: [
        {name: '{C#MODNAME}', files: ['users.js', 'explore.js', 'history.js']}
    ]
};
Component.entryPoint = function(NS){

    var Y = Brick.YUI,
        COMPONENT = this,
        SYS = Brick.mod.sys;

    NS.WorkspaceWidget = Y.Base.create('workspaceWidget', SYS.AppWidget, [
        SYS.AppWorkspace,
        NS.ContainerWidgetExt
    ], {
        onInitAppWidget: function(err, appInstance, options){
            var wsPage = new SYS.AppWorkspacePage(options.arguments[0].workspacePage),
                tp = this.template;

            this.set('waiting', true);

            appInstance.taskList(function(err, res){
                this.set('waiting', false);

                this.addWidget('explore', new NS.ExploreWidget({
                    srcNode: tp.gel('explore')
                }));

                appInstance.on('appResponses', this._onAppResponses, this);

                this.showWorkspacePage(!wsPage.isEmpty() ? wsPage : null);
                this.renderWidget();
            }, this);

        },
        destructor: function(){
            this.get('appInstance').detach('appResponses', this._onAppResponses, this);
        },
        _onAppResponses: function(e){
            if (e.err){
                return;
            }
            this.renderWidget();
        },
        renderWidget: function(){
            var tp = this.template,
                favoriteCount = 0,
                notReadedCount = 0,
                newCount = 0,
                changedCount = 0,
                newCommentCount = 0;

            this.get('appInstance').get('taskList').each(function(task){
                newCount += task.isNew() ? 1 : 0;
                changedCount += task.isChanged() ? 1 : 0;
                notReadedCount += !task.isReaded() ? 1 : 0;
                newCommentCount += task.isNewComment() ? 1 : 0;
                favoriteCount += task.isFavorite() ? 1 : 0;
            }, this);

            tp.setHTML({
                favoriteCount: favoriteCount,
                newCount: newCount,
                notReadedCount: notReadedCount,
                changedCount: changedCount,
                newCommentCount: newCommentCount
            });
        }
    }, {
        ATTRS: {
            component: {value: COMPONENT},
            templateBlockName: {value: 'widget'},
            defaultPage: {
                value: {
                    component: 'easylist',
                    widget: 'EasyListWidget'
                }
            }
        }
    });

    NS.ws = SYS.AppWorkspace.build('{C#MODNAME}', NS.WorkspaceWidget);
};
<commit_msg>bugfix: counter in ws menu<commit_after>var Component = new Brick.Component();
Component.requires = {
    mod: [
        {name: '{C#MODNAME}', files: ['users.js', 'explore.js', 'history.js']}
    ]
};
Component.entryPoint = function(NS){

    var Y = Brick.YUI,
        COMPONENT = this,
        SYS = Brick.mod.sys;

    NS.WorkspaceWidget = Y.Base.create('workspaceWidget', SYS.AppWidget, [
        SYS.AppWorkspace,
        NS.ContainerWidgetExt
    ], {
        onInitAppWidget: function(err, appInstance, options){
            var wsPage = new SYS.AppWorkspacePage(options.arguments[0].workspacePage),
                tp = this.template;

            this.set('waiting', true);

            appInstance.taskList(function(err, res){
                this.set('waiting', false);

                this.addWidget('explore', new NS.ExploreWidget({
                    srcNode: tp.gel('explore')
                }));

                appInstance.on('appResponses', this._onAppResponses, this);

                this.showWorkspacePage(!wsPage.isEmpty() ? wsPage : null);
                this.renderWidget();
            }, this);

        },
        destructor: function(){
            this.get('appInstance').detach('appResponses', this._onAppResponses, this);
        },
        _onAppResponses: function(e){
            if (e.err){
                return;
            }
            this.renderWidget();
        },
        renderWidget: function(){
            var tp = this.template,
                favoriteCount = 0,
                notReadedCount = 0,
                newCount = 0,
                changedCount = 0,
                newCommentCount = 0;

            this.get('appInstance').get('taskList').each(function(task){
                if (task.isRemoved()){
                    return;
                }
                newCount += task.isNew() ? 1 : 0;
                changedCount += task.isChanged() ? 1 : 0;
                notReadedCount += !task.isReaded() ? 1 : 0;
                newCommentCount += task.isNewComment() ? 1 : 0;
                favoriteCount += task.isFavorite() ? 1 : 0;
            }, this);

            tp.setHTML({
                favoriteCount: favoriteCount,
                newCount: newCount,
                notReadedCount: notReadedCount,
                changedCount: changedCount,
                newCommentCount: newCommentCount
            });
        }
    }, {
        ATTRS: {
            component: {value: COMPONENT},
            templateBlockName: {value: 'widget'},
            defaultPage: {
                value: {
                    component: 'easylist',
                    widget: 'EasyListWidget'
                }
            }
        }
    });

    NS.ws = SYS.AppWorkspace.build('{C#MODNAME}', NS.WorkspaceWidget);
};
<|endoftext|>


<commit_before>import React, { useEffect, useRef } from 'react'
import { connect as reduxConnect } from 'react-redux'

import { buildLogic, convertPartialDynamicInput, getIdForInput } from '../logic'
import { getContext } from '../context'

import { getLocalPlugins, runPlugins, reservedProxiedKeys } from '../plugins'

import { mountPaths, unmountPaths } from './mount'

function createWrapperFunction (input) {
  const wrapper = (Klass) => {
    const plugins = getLocalPlugins(input)

    runPlugins(plugins, 'beforeWrapper', input, Klass)

    // make this.actions work if it's a React.Component we're operating with
    injectActionsIntoClass(Klass)

    let isUnmounting = false
    let lastState

    const createConnect = reduxConnect(
      (state, ownProps) => {
        // At the moment when we unmount and detach from redux, react-redux will still be subscribed to the store
        // and will run this function to see if anything changed. Since we are detached from the store, all
        // selectors of this logic will crash. To avoid this, cache and return the last state.
        // Nothing will be rendered anywa.
        if (isUnmounting) {
          return lastState
        }

        // TODO: any better way to get it?
        const logic = buildLogic({ input, props: ownProps })

        let resp = {}
        Object.entries(logic.selectors).forEach(([key, selector]) => {
          resp[key] = selector(state, ownProps)
        })

        lastState = resp

        return resp
      },
      (dispatch, ownProps) => {
        // TODO: any better way to get it?
        const logic = buildLogic({ input, props: ownProps })

        let actions = Object.assign({}, ownProps.actions)

        Object.entries(logic.actions).forEach(([key, action]) => {
          actions[key] = (...args) => dispatch(action(...args))
        })

        return {
          dispatch: dispatch,
          actions: actions
        }
      }
    )
    const Connect = createConnect(Klass)

    // inject proptypes into the class if it's a React.Component
    // not using useRef here since we do it only once per component
    let injectPropTypes = !isStateless(Klass)

    const Kea = function (props) {
      // TODO: any better way to get it?
      const logic = buildLogic({ input, props, extendedInputs: wrapper._extendWith })

      // inject proptypes to React.Component
      if (injectPropTypes && logic.propTypes) {
        injectPropTypes = false
        Klass.propTypes = Object.assign(Klass.propTypes || {}, logic.propTypes)
      }

      // mount paths only on first render
      const firstRender = useRef(true)
      if (firstRender.current) {
        firstRender.current = false

        mountPaths(logic, plugins)
      }

      // unmount paths when component gets removed
      useEffect(() => {
        isUnmounting = false
        return () => {
          // set this as mapStateToProps can still run even if we have detached from redux
          isUnmounting = true
          unmountPaths(logic, plugins)
        }
      }, [])

      // TODO: unmount & remount if path changed
      runPlugins(plugins, 'beforeRender', logic, props)
      return <Connect {...props} />
    }

    Kea._wrapper = wrapper
    Kea._wrappedKlass = Klass

    runPlugins(plugins, 'afterWrapper', input, Klass, Kea)
    return Kea
  }

  return wrapper
}

export function kea (input) {
  const id = getIdForInput(input)
  getContext().inputs[id] = input

  const wrapper = createWrapperFunction(input)

  // TODO: legacy names. remove/change them?
  wrapper._isKeaFunction = true
  wrapper._isKeaSingleton = !input.key

  wrapper._extendWith = []
  wrapper.extend = (extendedInput) => {
    if (!input.key && !wrapper.mustBuild()) {
      throw new Error('[KEA] Can not extend logic once it has been built!')
    }
    wrapper._extendWith.push(extendedInput)
    return wrapper
  }

  if (input.key) {
    wrapper.withKey = keyCreator => {
      if (typeof keyCreator === 'function') {
        const buildWithProps = props => buildLogic({ input, key: keyCreator(props), props, extendedInputs: wrapper._extendWith })
        buildWithProps._isKeaWithKey = true
        return buildWithProps
      } else {
        return wrapper.buildWithKey(keyCreator)
      }
    }

    wrapper.buildWithKey = (key) => buildLogic({ input, key, extendedInputs: wrapper._extendWith })

    wrapper.mountWithKey = (key) => {
      const plugins = getLocalPlugins(input)
      const logic = wrapper.buildWithKey(key)

      mountPaths(logic, plugins)
      return () => unmountPaths(logic, plugins)
    }

    Object.assign(wrapper, convertPartialDynamicInput({ input }))
  } else {
    const { proxyFields } = getContext()

    wrapper.mustBuild = () => {
      const { state } = getContext()
      const id = getIdForInput(input)

      return !state[id] || !state[id].logic
    }

    wrapper.build = (props) => {
      const { state } = getContext()
      const id = getIdForInput(input)

      if (state[id] && state[id].logic) {
        return state[id].logic
      }

      const logic = buildLogic({ input, extendedInputs: wrapper._extendWith })

      state[id] = state[id] ? { ...state[id], logic } : { logic }

      return logic
    }

    wrapper.mount = () => {
      const logic = wrapper.build()
      const plugins = getLocalPlugins(input)

      mountPaths(logic, plugins)
      return () => unmountPaths(logic, plugins)
    }

    if (proxyFields) {
      const plugins = getLocalPlugins(input)
      const { logicKeys } = plugins
      for (const key of Object.keys(logicKeys)) {
        proxyFieldToLogic(wrapper, key)
      }
      for (const key of reservedProxiedKeys) {
        proxyFieldToLogic(wrapper, key)
      }
    }
  }

  if (getContext().autoMount && wrapper.mount) {
    wrapper.mount()
  }

  return wrapper
}

export function connect (input) {
  return kea({ connect: input })
}

function isStateless (Component) {
  return (
    typeof Component === 'function' && // can be various things
    !(Component.prototype && Component.prototype.isReactComponent) // native arrows don't have prototypes // special property
  )
}

// inject to the component something that converts this.props.actions to this.actions
function injectActionsIntoClass (Klass) {
  if (!isStateless(Klass)) {
    if (!Object.getOwnPropertyDescriptor(Klass.prototype, 'actions')) {
      Object.defineProperty(Klass.prototype, 'actions', {
        get: function actions () {
          return this.props.actions
        }
      })
    }
  }
}

function proxyFieldToLogic (wrapper, key) {
  Object.defineProperty(wrapper, key, {
    get: function actions () {
      return wrapper.build()[key]
    }
  })
}
<commit_msg>isUnmounting fix<commit_after>import React, { useEffect, useRef } from 'react'
import { connect as reduxConnect } from 'react-redux'

import { buildLogic, convertPartialDynamicInput, getIdForInput } from '../logic'
import { getContext } from '../context'

import { getLocalPlugins, runPlugins, reservedProxiedKeys } from '../plugins'

import { mountPaths, unmountPaths } from './mount'

function createWrapperFunction (input) {
  const wrapper = (Klass) => {
    const plugins = getLocalPlugins(input)

    runPlugins(plugins, 'beforeWrapper', input, Klass)

    // make this.actions work if it's a React.Component we're operating with
    injectActionsIntoClass(Klass)

    let isUnmounting = false
    let lastState

    const createConnect = reduxConnect(
      (state, ownProps) => {
        // At the moment when we unmount and detach from redux, react-redux will still be subscribed to the store
        // and will run this function to see if anything changed. Since we are detached from the store, all
        // selectors of this logic will crash. To avoid this, cache and return the last state.
        // Nothing will be rendered anywa.
        if (isUnmounting) {
          return lastState
        }

        // TODO: any better way to get it?
        const logic = buildLogic({ input, props: ownProps })

        let resp = {}
        Object.entries(logic.selectors).forEach(([key, selector]) => {
          resp[key] = selector(state, ownProps)
        })

        lastState = resp

        return resp
      },
      (dispatch, ownProps) => {
        // TODO: any better way to get it?
        const logic = buildLogic({ input, props: ownProps })

        let actions = Object.assign({}, ownProps.actions)

        Object.entries(logic.actions).forEach(([key, action]) => {
          actions[key] = (...args) => dispatch(action(...args))
        })

        return {
          dispatch: dispatch,
          actions: actions
        }
      }
    )
    const Connect = createConnect(Klass)

    // inject proptypes into the class if it's a React.Component
    // not using useRef here since we do it only once per component
    let injectPropTypes = !isStateless(Klass)

    const Kea = function (props) {
      // TODO: any better way to get it?
      const logic = buildLogic({ input, props, extendedInputs: wrapper._extendWith })

      // inject proptypes to React.Component
      if (injectPropTypes && logic.propTypes) {
        injectPropTypes = false
        Klass.propTypes = Object.assign(Klass.propTypes || {}, logic.propTypes)
      }

      // mount paths only on first render
      const firstRender = useRef(true)
      if (firstRender.current) {
        firstRender.current = false

        mountPaths(logic, plugins)
      }

      // unmount paths when component gets removed
      useEffect(() => () => {
        // set this as mapStateToProps can still run even if we have detached from redux
        isUnmounting = true
        unmountPaths(logic, plugins)
        isUnmounting = false
      }, [])

      // TODO: unmount & remount if path changed
      runPlugins(plugins, 'beforeRender', logic, props)
      return <Connect {...props} />
    }

    Kea._wrapper = wrapper
    Kea._wrappedKlass = Klass

    runPlugins(plugins, 'afterWrapper', input, Klass, Kea)
    return Kea
  }

  return wrapper
}

export function kea (input) {
  const id = getIdForInput(input)
  getContext().inputs[id] = input

  const wrapper = createWrapperFunction(input)

  // TODO: legacy names. remove/change them?
  wrapper._isKeaFunction = true
  wrapper._isKeaSingleton = !input.key

  wrapper._extendWith = []
  wrapper.extend = (extendedInput) => {
    if (!input.key && !wrapper.mustBuild()) {
      throw new Error('[KEA] Can not extend logic once it has been built!')
    }
    wrapper._extendWith.push(extendedInput)
    return wrapper
  }

  if (input.key) {
    wrapper.withKey = keyCreator => {
      if (typeof keyCreator === 'function') {
        const buildWithProps = props => buildLogic({ input, key: keyCreator(props), props, extendedInputs: wrapper._extendWith })
        buildWithProps._isKeaWithKey = true
        return buildWithProps
      } else {
        return wrapper.buildWithKey(keyCreator)
      }
    }

    wrapper.buildWithKey = (key) => buildLogic({ input, key, extendedInputs: wrapper._extendWith })

    wrapper.mountWithKey = (key) => {
      const plugins = getLocalPlugins(input)
      const logic = wrapper.buildWithKey(key)

      mountPaths(logic, plugins)
      return () => unmountPaths(logic, plugins)
    }

    Object.assign(wrapper, convertPartialDynamicInput({ input }))
  } else {
    const { proxyFields } = getContext()

    wrapper.mustBuild = () => {
      const { state } = getContext()
      const id = getIdForInput(input)

      return !state[id] || !state[id].logic
    }

    wrapper.build = (props) => {
      const { state } = getContext()
      const id = getIdForInput(input)

      if (state[id] && state[id].logic) {
        return state[id].logic
      }

      const logic = buildLogic({ input, extendedInputs: wrapper._extendWith })

      state[id] = state[id] ? { ...state[id], logic } : { logic }

      return logic
    }

    wrapper.mount = () => {
      const logic = wrapper.build()
      const plugins = getLocalPlugins(input)

      mountPaths(logic, plugins)
      return () => unmountPaths(logic, plugins)
    }

    if (proxyFields) {
      const plugins = getLocalPlugins(input)
      const { logicKeys } = plugins
      for (const key of Object.keys(logicKeys)) {
        proxyFieldToLogic(wrapper, key)
      }
      for (const key of reservedProxiedKeys) {
        proxyFieldToLogic(wrapper, key)
      }
    }
  }

  if (getContext().autoMount && wrapper.mount) {
    wrapper.mount()
  }

  return wrapper
}

export function connect (input) {
  return kea({ connect: input })
}

function isStateless (Component) {
  return (
    typeof Component === 'function' && // can be various things
    !(Component.prototype && Component.prototype.isReactComponent) // native arrows don't have prototypes // special property
  )
}

// inject to the component something that converts this.props.actions to this.actions
function injectActionsIntoClass (Klass) {
  if (!isStateless(Klass)) {
    if (!Object.getOwnPropertyDescriptor(Klass.prototype, 'actions')) {
      Object.defineProperty(Klass.prototype, 'actions', {
        get: function actions () {
          return this.props.actions
        }
      })
    }
  }
}

function proxyFieldToLogic (wrapper, key) {
  Object.defineProperty(wrapper, key, {
    get: function actions () {
      return wrapper.build()[key]
    }
  })
}
<|endoftext|>


<commit_before>import models from 'src/server/db/models'
import hashids from 'src/shared/utils/hashids-plus'
import moment from 'moment'
import { sortBy, uniq, pluck, range, compact, reduce, isEmpty } from 'lodash'

const Sequelize = models.Sequelize
const Post = models.posts

exports.create = function *(post) {
  const fillable = [
    'uid',
    'type',
    'prop',
    'startDate',
    'endDate',
    'openDate',
    'closeDate',
    'dateType',
    'title',
    'content',
    'file',
    'lat',
    'lng',
    'place',
    'url',
    'status'
  ]

  return yield Post.create(post, { fields: fillable })
}

exports.load = function *(hid) {
  const id = +hashids.decode(hid)
  return yield Post.findOne({
    where: { id: id }
  })
}

/* eslint-disable camelcase */
exports.list = function *(offset=0, limit=20) {
  const _start = moment().startOf('day').valueOf()
  return yield Post.findAll({
    offset: offset,
    limit: limit,
    order: [[ 'start_date', 'ASC' ]],
    where: {
      end_date: {
        $gte: new Date(moment(_start))
      }
    }
  })
}

/* eslint-disable camelcase */
exports.listWithCprop = function *(cprop, offset=0, limit=20) {
  if (cprop === null) return []

  return yield Post.findAll({
    offset: offset,
    limit: limit,
    order: [[ 'end_date', 'DESC' ]],
    where: {
      prop: +cprop
    }
  })
}

/* eslint-disable camelcase */
exports.listWithUser = function *(offset=0, limit=20, uid) {
  if (uid === null) return []

  return yield Post.findAll({
    offset: offset,
    limit: limit,
    order: [[ 'end_date', 'DESC' ]],
    where: {
      uid: +uid
    }
  })
}

/* eslint-disable camelcase */
exports.fetch = function *(offset=0, limit=20, start, end) {
  let _start = start
  let _end = end

  if (_start !== null) {
    _start = moment().startOf('day').valueOf()
  } else {
    _start = +_start
  }
  if (_end !== null) {
    _end = moment(+_start).endOf('day').valueOf()
  } else {
    _end = +_end
  }

  const startItems = yield Post.findAll({
    offset: offset,
    limit: limit,
    order: [[ 'end_date', 'ASC' ]],
    where: {
      start_date: {
        $between: [
          new Date(moment(_start).startOf('day')),
          new Date(moment(_start).endOf('day'))
        ]
      }
    },
    raw: true
  })

  const endItems = yield Post.findAll({
    offset: offset,
    limit: limit,
    order: [[ 'end_date', 'ASC' ]],
    where: {
      end_date: {
        $between: [
          new Date(moment(_end).startOf('day')),
          new Date(moment(_end).endOf('day'))
        ]
      }
    },
    raw: true
  })

  const duringItems = yield Post.findAll({
    offset: offset,
    limit: limit,
    order: [[ 'end_date', 'ASC' ]],
    where: {
      start_date: {
        $lt:
          new Date(moment(_start).startOf('day'))
      },
      end_date: {
        $gt:
          new Date(moment(_end).startOf('day'))
      }
    },
    raw: true
  })

  let final = []
  final = final.concat(startItems)
  final = final.concat(endItems)
  final = final.concat(duringItems)
  final = uniq(final, (item, key, id) => item.id )
  final = sortBy(final, 'endDate')

  return final
}

/* eslint-disable camelcase */
exports.fetchWithUser = function *(offset=0, limit=20, start, end, uid) {
  if (!uid) return []

  let _start = start
  let _end = end

  if (_start !== null) {
    _start = moment().startOf('day').valueOf()
  } else {
    _start = +_start
  }
  if (_end !== null) {
    _end = moment(+_start).endOf('day').valueOf()
  } else {
    _end = +_end
  }

  return yield Post.findAll({
    offset: offset,
    limit: limit,
    order: [[ 'id', 'DESC' ]],
    where: {
      uid: +uid,
      end_date: {
        $gte: new Date(moment(_start))
      }
    }
  })
}

/* eslint-disable camelcase */
exports.countPerDayInMonth = function *(year, month) {
  const out = []
  const startDateOut = []
  let _year = year
  let _month = month
  let totalDays

  if (_year !== 'undefined' && _month !== 'undefined') {
    totalDays = moment({
      year: _year,
      month: _month - 1,
      day: 1
    }).endOf('month').date()
  } else {
    totalDays = moment().endOf('month').date()
    _year = moment().year()
    _month = moment().month() + 1
  }

  const startItems = yield Post.findAll({
    attributes: [
      'startDate',
      'endDate'
    ],
    order: [[ 'start_date', 'ASC' ]],
    where: {
      start_date: {
        $between: [
          new Date(moment({
            year: _year,
            month: _month - 1,
            day: 1
          }).startOf('day')),
          new Date(moment({
            year: _year,
            month: _month - 1,
            day: totalDays
          }).endOf('day'))
        ]
      }
    },
    raw: true
  })

  const endItems = yield Post.findAll({
    attributes: [
      'startDate',
      'endDate'
    ],
    order: [[ 'start_date', 'ASC' ]],
    where: {
      start_date: {
        $notBetween: [
          new Date(moment({
            year: _year,
            month: _month - 1,
            day: 1
          }).startOf('day')),
          new Date(moment({
            year: _year,
            month: _month - 1,
            day: totalDays
          }).endOf('day'))
        ]
      },
      end_date: {
        $between: [
          new Date(moment({
            year: _year,
            month: _month - 1,
            day: 1
          }).startOf('day')),
          new Date(moment({
            year: _year,
            month: _month - 1,
            day: totalDays
          }).endOf('day'))
        ]
      }
    },
    raw: true
  })

  const duringItems = yield Post.findAll({
    attributes: [
      'startDate',
      'endDate'
    ],
    order: [[ 'start_date', 'ASC' ]],
    where: {
      start_date: {
        $lt:
          new Date(moment({
            year: _year,
            month: _month - 1,
            day: 1
          }).startOf('day'))
      },
      end_date: {
        $gt:
          new Date(moment({
            year: _year,
            month: _month - 1,
            day: totalDays
          }).endOf('day'))
      }
    },
    raw: true
  })

  startItems.forEach(item => {
    const start = moment(new Date(item.startDate)).date()
    const _diff = moment(new Date(item.endDate))
      .diff(new Date(item.startDate), 'days')

    if (_diff >= 0) {
      for (const i of range(start, start + _diff + 1)) {
        if (typeof out[i] === 'undefined') {
          out[i] = 1
        } else {
          out[i] = out[i] + 1
        }
      }
    } else {
      if (typeof out[start] === 'undefined') {
        out[start] = 1
      } else {
        out[start] = out[start] + 1
      }
    }

    startDateOut[start] = 1
  })

  endItems.forEach(item => {
    const start = 1
    const _diff = moment(new Date(item.endDate))
      .diff(moment(new Date(item.endDate)).startOf('month'), 'days')

    if (_diff >= 0) {
      for (const i of range(start, start + _diff + 1))
        if (typeof out[i] === 'undefined') {
          out[i] = 1
        } else {
          out[i] = out[i] + 1
        }
    }
  })

  duringItems.forEach(item => {
    const start = 1
    const _diff = moment({
      year: _year,
      month: _month - 1,
      day: totalDays
    })
    .diff(moment({
      year: _year,
      month: _month - 1,
      day: 1
    })
    , 'days')

    if (_diff >= 0) {
      for (const i of range(start, start + _diff + 1))
        if (typeof out[i] === 'undefined') {
          out[i] = 1
        } else {
          out[i] = out[i] + 1
        }
    }
  })

  // Total in this month
  out[0] = reduce(compact(out), (sum, n) => sum + n )

  return { count: out, countStart: startDateOut }
}

function date_format (date, fm) {
  return moment(date).format(fm)
}

exports.update = function *(hid, post) {
  const fillable = [
    'type',
    'prop',
    'startDate',
    'endDate',
    'openDate',
    'closeDate',
    'dateType',
    'title',
    'content',
    'file',
    'lat',
    'lng',
    'place',
    'url',
    'status'
  ]
  const id = +hashids.decode(hid)
  const p = yield Post.findOne({
    where: { id: id }
  })
  return yield p.update(post, { fields: fillable })
}

exports.destroy = function *(hid) {
  const id = +hashids.decode(hid)
  const post = yield Post.findOne({ where: { id: id } })
  return yield post.destroy()
}

exports.updateGeo = function *(hid, geo) {
  const fillable = [
    'lat',
    'lng',
    'country',
    'city',
    'place',
    'zipcode',
    'address'
  ]
  const id = +hashids.decode(hid)
  const p = yield Post.findOne({
    where: { id: id }
  })
  return yield p.update(geo, { fields: fillable })
}

exports.updateAttachments = function *(hid, attach) {
  const fillable = [ 'url', 'img', 'file' ]
  const id = +hashids.decode(hid)
  const p = yield Post.findOne({
    where: { id: id }
  })
  return yield p.update(attach, { fields: fillable })
}

/* eslint-disable camelcase */
exports.search = function *(pattern, offset=0, limit=20) {
  return yield Post.findAll({
    offset: offset,
    limit: limit,
    order: [[ 'start_date', 'ASC' ]],
    where: {
      $or: [
        {
          title: {
            $like: '%' + pattern + '%'
          }
        },
        {
          content: {
            $like: '%' + pattern + '%'
          }
        }
      ]
    }
  })
}
<commit_msg>fix typo<commit_after>import models from 'src/server/db/models'
import hashids from 'src/shared/utils/hashids-plus'
import moment from 'moment'
import { sortBy, uniq, pluck, range, compact, reduce, isEmpty } from 'lodash'

const Sequelize = models.Sequelize
const Post = models.posts

exports.create = function *(post) {
  const fillable = [
    'uid',
    'type',
    'prop',
    'startDate',
    'endDate',
    'openDate',
    'closeDate',
    'dateType',
    'title',
    'content',
    'file',
    'lat',
    'lng',
    'place',
    'url',
    'status'
  ]

  return yield Post.create(post, { fields: fillable })
}

exports.load = function *(hid) {
  const id = +hashids.decode(hid)
  return yield Post.findOne({
    where: { id: id }
  })
}

/* eslint-disable camelcase */
exports.list = function *(offset=0, limit=20) {
  const _start = moment().startOf('day').valueOf()
  return yield Post.findAll({
    offset: offset,
    limit: limit,
    order: [[ 'start_date', 'ASC' ]],
    where: {
      end_date: {
        $gte: new Date(moment(_start))
      }
    }
  })
}

/* eslint-disable camelcase */
exports.listWithCprop = function *(cprop, offset=0, limit=20) {
  if (cprop === null) return []

  return yield Post.findAll({
    offset: offset,
    limit: limit,
    order: [[ 'end_date', 'DESC' ]],
    where: {
      prop: +cprop
    }
  })
}

/* eslint-disable camelcase */
exports.listWithUser = function *(offset=0, limit=20, uid) {
  if (uid === null) return []

  return yield Post.findAll({
    offset: offset,
    limit: limit,
    order: [[ 'end_date', 'DESC' ]],
    where: {
      uid: +uid
    }
  })
}

/* eslint-disable camelcase */
exports.fetch = function *(offset=0, limit=20, start, end) {
  let _start = start
  let _end = end

  if (_start !== null) {
    _start = moment().startOf('day').valueOf()
  } else {
    _start = +_start
  }
  if (_end !== null) {
    _end = moment(+_start).endOf('day').valueOf()
  } else {
    _end = +_end
  }

  const startItems = yield Post.findAll({
    offset: offset,
    limit: limit,
    order: [[ 'end_date', 'ASC' ]],
    where: {
      start_date: {
        $between: [
          new Date(moment(_start).startOf('day')),
          new Date(moment(_start).endOf('day'))
        ]
      }
    },
    raw: true
  })

  const endItems = yield Post.findAll({
    offset: offset,
    limit: limit,
    order: [[ 'end_date', 'ASC' ]],
    where: {
      end_date: {
        $between: [
          new Date(moment(_end).startOf('day')),
          new Date(moment(_end).endOf('day'))
        ]
      }
    },
    raw: true
  })

  const duringItems = yield Post.findAll({
    offset: offset,
    limit: limit,
    order: [[ 'end_date', 'ASC' ]],
    where: {
      start_date: {
        $lt:
          new Date(moment(_start).startOf('day'))
      },
      end_date: {
        $gt:
          new Date(moment(_end).startOf('day'))
      }
    },
    raw: true
  })

  let final = []
  final = final.concat(startItems)
  final = final.concat(endItems)
  final = final.concat(duringItems)
  final = uniq(final, (item, key, id) => item.id )
  final = sortBy(final, 'endDate')

  return final
}

/* eslint-disable camelcase */
exports.fetchWithUser = function *(offset=0, limit=20, start, end, uid) {
  if (!uid) return []

  let _start = start
  let _end = end

  if (_start !== null) {
    _start = moment().startOf('day').valueOf()
  } else {
    _start = +_start
  }
  if (_end !== null) {
    _end = moment(+_start).endOf('day').valueOf()
  } else {
    _end = +_end
  }

  return yield Post.findAll({
    offset: offset,
    limit: limit,
    order: [[ 'id', 'DESC' ]],
    where: {
      uid: +uid,
      end_date: {
        $gte: new Date(moment(_start))
      }
    }
  })
}

/* eslint-disable camelcase */
exports.countPerDayInMonth = function *(year, month) {
  const out = []
  const startDateOut = []
  let _year = year
  let _month = month
  let totalDays

  if (typeof _year !== 'undefined' && typeof _month !== 'undefined') {
    totalDays = moment({
      year: _year,
      month: _month - 1,
      day: 1
    }).endOf('month').date()
  } else {
    totalDays = moment().endOf('month').date()
    _year = moment().year()
    _month = moment().month() + 1
  }

  const startItems = yield Post.findAll({
    attributes: [
      'startDate',
      'endDate'
    ],
    order: [[ 'start_date', 'ASC' ]],
    where: {
      start_date: {
        $between: [
          new Date(moment({
            year: _year,
            month: _month - 1,
            day: 1
          }).startOf('day')),
          new Date(moment({
            year: _year,
            month: _month - 1,
            day: totalDays
          }).endOf('day'))
        ]
      }
    },
    raw: true
  })

  const endItems = yield Post.findAll({
    attributes: [
      'startDate',
      'endDate'
    ],
    order: [[ 'start_date', 'ASC' ]],
    where: {
      start_date: {
        $notBetween: [
          new Date(moment({
            year: _year,
            month: _month - 1,
            day: 1
          }).startOf('day')),
          new Date(moment({
            year: _year,
            month: _month - 1,
            day: totalDays
          }).endOf('day'))
        ]
      },
      end_date: {
        $between: [
          new Date(moment({
            year: _year,
            month: _month - 1,
            day: 1
          }).startOf('day')),
          new Date(moment({
            year: _year,
            month: _month - 1,
            day: totalDays
          }).endOf('day'))
        ]
      }
    },
    raw: true
  })

  const duringItems = yield Post.findAll({
    attributes: [
      'startDate',
      'endDate'
    ],
    order: [[ 'start_date', 'ASC' ]],
    where: {
      start_date: {
        $lt:
          new Date(moment({
            year: _year,
            month: _month - 1,
            day: 1
          }).startOf('day'))
      },
      end_date: {
        $gt:
          new Date(moment({
            year: _year,
            month: _month - 1,
            day: totalDays
          }).endOf('day'))
      }
    },
    raw: true
  })

  startItems.forEach(item => {
    const start = moment(new Date(item.startDate)).date()
    const _diff = moment(new Date(item.endDate))
      .diff(new Date(item.startDate), 'days')

    if (_diff >= 0) {
      for (const i of range(start, start + _diff + 1)) {
        if (typeof out[i] === 'undefined') {
          out[i] = 1
        } else {
          out[i] = out[i] + 1
        }
      }
    } else {
      if (typeof out[start] === 'undefined') {
        out[start] = 1
      } else {
        out[start] = out[start] + 1
      }
    }

    startDateOut[start] = 1
  })

  endItems.forEach(item => {
    const start = 1
    const _diff = moment(new Date(item.endDate))
      .diff(moment(new Date(item.endDate)).startOf('month'), 'days')

    if (_diff >= 0) {
      for (const i of range(start, start + _diff + 1))
        if (typeof out[i] === 'undefined') {
          out[i] = 1
        } else {
          out[i] = out[i] + 1
        }
    }
  })

  duringItems.forEach(item => {
    const start = 1
    const _diff = moment({
      year: _year,
      month: _month - 1,
      day: totalDays
    })
    .diff(moment({
      year: _year,
      month: _month - 1,
      day: 1
    })
    , 'days')

    if (_diff >= 0) {
      for (const i of range(start, start + _diff + 1))
        if (typeof out[i] === 'undefined') {
          out[i] = 1
        } else {
          out[i] = out[i] + 1
        }
    }
  })

  // Total in this month
  out[0] = reduce(compact(out), (sum, n) => sum + n )

  return { count: out, countStart: startDateOut }
}

function date_format (date, fm) {
  return moment(date).format(fm)
}

exports.update = function *(hid, post) {
  const fillable = [
    'type',
    'prop',
    'startDate',
    'endDate',
    'openDate',
    'closeDate',
    'dateType',
    'title',
    'content',
    'file',
    'lat',
    'lng',
    'place',
    'url',
    'status'
  ]
  const id = +hashids.decode(hid)
  const p = yield Post.findOne({
    where: { id: id }
  })
  return yield p.update(post, { fields: fillable })
}

exports.destroy = function *(hid) {
  const id = +hashids.decode(hid)
  const post = yield Post.findOne({ where: { id: id } })
  return yield post.destroy()
}

exports.updateGeo = function *(hid, geo) {
  const fillable = [
    'lat',
    'lng',
    'country',
    'city',
    'place',
    'zipcode',
    'address'
  ]
  const id = +hashids.decode(hid)
  const p = yield Post.findOne({
    where: { id: id }
  })
  return yield p.update(geo, { fields: fillable })
}

exports.updateAttachments = function *(hid, attach) {
  const fillable = [ 'url', 'img', 'file' ]
  const id = +hashids.decode(hid)
  const p = yield Post.findOne({
    where: { id: id }
  })
  return yield p.update(attach, { fields: fillable })
}

/* eslint-disable camelcase */
exports.search = function *(pattern, offset=0, limit=20) {
  return yield Post.findAll({
    offset: offset,
    limit: limit,
    order: [[ 'start_date', 'ASC' ]],
    where: {
      $or: [
        {
          title: {
            $like: '%' + pattern + '%'
          }
        },
        {
          content: {
            $like: '%' + pattern + '%'
          }
        }
      ]
    }
  })
}
<|endoftext|>


<commit_before>const _ = require('lodash')
// const X2Js = require('x2js')
const { getEntity } = require('@robotopia/choo-game')

function checkGoal ({ goal, game, workspace }) {
  switch (goal.type) {
    case 'moveTo':
      if (game === null) {
        return false
      }

      const entity = getEntity(goal.params.entity, game)
      const entityPos = { x: entity.position.x, y: entity.position.y }

      return _.isEqual(entityPos, goal.params.position)

    case 'useBlock':
      return workspace.indexOf(goal.params.type) > -1

    case 'doNotUseBlock':
      return workspace.indexOf(goal.params.type) === -1

    case 'maxBlocks':
      const workspaceMatch = workspace.match(/<block/g)

      if (workspaceMatch) {
        return workspaceMatch.length <= goal.params.amount
      }
      return false

    case 'carryResource':
      if (game && game.entities) {
        return game.entities.ROBOT.collector.hasResource === goal.params.hasResource
      }
      return false

    case 'collectResources':
      if (game && game.teams) {
        return game.teams[game.entities.ROBOT.team.id].resources === goal.params.amount
      }
      return false

    case 'dontTouchTileType':
      // TODO: check for robot touching dirt upon walking
      // goal.params.tileID
      return false

    case 'useBlockWithinBlock':
      // TODO: workspace to json, check for outer block. Stringify outer blocks statement object and regex the inner block.
      // const workspaceAsJSON = new X2Js().xml_str2json(workspace);
      // goal.params.outerBlock
      // goal.params.innerBlock
      // console.log(workspaceAsJSON)
      return false

    case 'discoverEntityOfType':
      if (!game || !game.entities || game.entities.length === 0) return false
      let i
      for (i in game.entities) {
        if (game.entities[i].hasOwnProperty('discoverable')) {
          let discoverable = game.entities[i].discoverable
          if (discoverable.type === goal.params.type && discoverable.discovererTeamIds && discoverable.discovererTeamIds['1']) return true
        }
      }
      return false

    default:
      return false
  }
}

function checkGoals ({ game, workspace }, goals) {
  return _.every(goals, (goal) => checkGoal({ goal, game, workspace }))
}

module.exports = {
  checkGoal,
  checkGoals
}
<commit_msg>tileTouched works now<commit_after>const _ = require('lodash')
// const X2Js = require('x2js')
const { getEntity } = require('@robotopia/choo-game')
let haventTouchedTile = true

function checkGoal ({ goal, game, workspace }) {
  switch (goal.type) {
    case 'moveTo':
      if (game === null) {
        return false
      }

      const entity = getEntity(goal.params.entity, game)
      const entityPos = { x: entity.position.x, y: entity.position.y }

      return _.isEqual(entityPos, goal.params.position)

    case 'useBlock':
      return workspace.indexOf(goal.params.type) > -1

    case 'doNotUseBlock':
      return workspace.indexOf(goal.params.type) === -1

    case 'maxBlocks':
      const workspaceMatch = workspace.match(/<block/g)

      if (workspaceMatch) {
        return workspaceMatch.length <= goal.params.amount
      }
      return false

    case 'carryResource':
      if (game && game.entities) {
        return game.entities.ROBOT.collector.hasResource === goal.params.hasResource
      }
      return false

    case 'collectResources':
      if (game && game.teams) {
        return game.teams[game.entities.ROBOT.team.id].resources === goal.params.amount
      }
      return false

    case 'dontTouchTileType':
      if (game && haventTouchedTile) {
        const robotPosition = game.entities.ROBOT.position
        const currTile = game.tiles[robotPosition.y][robotPosition.x]

        haventTouchedTile = goal.params.tileID !== currTile
      }

      if (!game) {
        haventTouchedTile = true
      }

      return haventTouchedTile

    case 'useBlockWithinBlock':
      // TODO: workspace to json, check for outer block. Stringify outer blocks statement object and regex the inner block.
      // const workspaceAsJSON = new X2Js().xml_str2json(workspace);
      // goal.params.outerBlock
      // goal.params.innerBlock
      // console.log(workspaceAsJSON)
      return false

    case 'discoverEntityOfType':
      if (!game || !game.entities || game.entities.length === 0) return false
      let i
      for (i in game.entities) {
        if (game.entities[i].hasOwnProperty('discoverable')) {
          let discoverable = game.entities[i].discoverable
          if (discoverable.type === goal.params.type && discoverable.discovererTeamIds && discoverable.discovererTeamIds['1']) return true
        }
      }
      return false

    default:
      return false
  }
}

function checkGoals ({ game, workspace }, goals) {
  return _.every(goals, (goal) => checkGoal({ goal, game, workspace }))
}

module.exports = {
  checkGoal,
  checkGoals
}
<|endoftext|>