<commit_before>var redis = require('redis'),
    client = redis.createClient();

client.on('error', function (err) {
    console.log('Error ' + err);
});

// If no key specified, use filename for some degree of uniqueness
var key = process.env.DBKEY || __filename;

exports.get = function(id, fn) {
  client.get(key, function(err, reply) {
    if (err) return fn(err);
    console.log(reply);
    reply = JSON.parse(reply);
    if (!reply || !reply[id]) return fn(new Error('Not found'));
    fn(null, reply[id]);
  });
};

exports.post = function(docs, fn) {
  // uncomment to reset
  //client.del(key);
  client.get(key, function(err, reply) {
    if (err) return fn(err);
    reply = JSON.parse(reply) || {};
    merge(reply, docs);
    client.set(key, JSON.stringify(reply), function(err, setReply) {
      if (err) return fn(err);
      fn(null, setReply);
    });
  });
};

exports.near = function(lat, lng, fn) {
  client.get(key, function(err, reply) {
    if (err) return fn(err);
    var db = JSON.parse(reply);
    for (var id in db) {
      locObj[id].id = id;
      locations.push(locObj[id]);
    }
    fn(null, locations);
  });
};

exports.loc = function(idOrSlug, fn) {
  exports.get(idOrSlug, function(err, data) {
    if (err) return exports.getBySlug(idOrSlug, fn);
    fn(null, data);
  });
};

exports.getBySlug = function(slug, fn) {
  request({
    url: encodeURI('https://api.cloudmine.me/v1/app/'+process.env.CMID+'/search?q=[slug="'+slug+'"]'),
    headers: {'X-CloudMine-ApiKey': process.env.CMKEY}
  }, function(err, res, body) {
    if (err) return fn(err);
    if (_.isEmpty(JSON.parse(body).success)) return fn(body);
    fn(null, body);
  });
};

exports.settings = function(doc, fn) {
  // get settings if no doc param
  if (!fn) {
    fn = doc;
    return exports.get('settings', function(err, data){
      if (err) return fn(err);
      fn(null, data);
    });
  }
  exports.post({settings: doc}, fn);
};

function merge(a, b) {
  if (a && b) {
    for (var key in b) {
      a[key] = b[key];
    }
  }
  return a;
}
<commit_msg>Distance work<commit_after>var redis = require('redis'),
    client = redis.createClient();

client.on('error', function (err) {
    console.log('Error ' + err);
});

// If no key specified, use filename for some degree of uniqueness
var key = process.env.DBKEY || __filename;

exports.get = function(id, fn) {
  client.get(key, function(err, reply) {
    if (err) return fn(err);
    console.log(reply);
    reply = JSON.parse(reply);
    if (!reply || !reply[id]) return fn(new Error('Not found'));
    fn(null, reply[id]);
  });
};

exports.post = function(docs, fn) {
  // uncomment to reset
  //client.del(key);
  client.get(key, function(err, reply) {
    if (err) return fn(err);
    reply = JSON.parse(reply) || {};
    merge(reply, docs);
    client.set(key, JSON.stringify(reply), function(err, setReply) {
      if (err) return fn(err);
      fn(null, setReply);
    });
  });
};

exports.near = function(lat, lon, limit, fn) {
  var _limit;
  if (fn) {
    _limit = limit || 20;
  } else {
    fn = limit;
    _limit = 20;
  }
  client.get(key, function(err, reply) {
    if (err) return fn(err);
    var db = JSON.parse(reply);
    var doc, distance, distances = [];
    for (var id in db) {
      doc = db[id];
      if (doc.location) {
        distance = getDistance(lat, doc.location.lat, lon, doc.location.lon)
        distances.push(distance)
        distances.sort()
        // TODO link distances to IDs
        if (distances.length > _limit) distances.pop();
      }
      //locObj[id].id = id;
      //locations.push(locObj[id]);
    }
    fn(null, distances);
  });
};

exports.loc = function(idOrSlug, fn) {
  exports.get(idOrSlug, function(err, data) {
    if (err) return exports.getBySlug(idOrSlug, fn);
    fn(null, data);
  });
};

exports.getBySlug = function(slug, fn) {
  //request({
  //  url: encodeURI('https://api.cloudmine.me/v1/app/'+process.env.CMID+'/search?q=[slug="'+slug+'"]'),
  //  headers: {'X-CloudMine-ApiKey': process.env.CMKEY}
  //}, function(err, res, body) {
  //  if (err) return fn(err);
  //  if (_.isEmpty(JSON.parse(body).success)) return fn(body);
  //  fn(null, body);
  //});
};

exports.settings = function(doc, fn) {
  // get settings if no doc param
  if (!fn) {
    fn = doc;
    return exports.get('settings', function(err, data){
      if (err) return fn(err);
      fn(null, data);
    });
  }
  exports.post({settings: doc}, fn);
};

function getDistance(x1, y1, x2, y2) {
  function sq(x) {return x*x}
  return Math.sqrt(sq(x2-x1)+sq(y2-y1))
}

function merge(a, b) {
  if (a && b) {
    for (var key in b) {
      a[key] = b[key];
    }
  }
  return a;
}
<|endoftext|>


<commit_before>/**
 * controller
 * @return
 */
module.exports = Controller("Home/BaseController", function(){
  "use strict";
  var Service = require("../../Service/Service");
  var captchapng = require('captchapng');

  return {
    updateAction: function(){
      var self = this;
      if(self.isGet()){
        return self.redirect("/");
      }else if(self.isPost()){
        var user_id = self.post('id');
        return self.session('userInfo').then(function(value){
          if (!isEmpty(value)) {
            if(value.id == user_id){
              return Service.updateUserById(self.post()).then(function(content){
                if(content == 0){
                  return self.success()
                }else if(content == -1){
                  throw new Error('没有找到该用户！')
                }
              }).catch(function(err){
                return self.error(err.message || "系统异常，请稍后再试！")
              })
            }else{
              self.session('userInfo', '');
              self.redirect('/');
            }
          }else{
            self.redirect('/');
          }
        })
      }
    },

    logoutAction: function() {
      var self = this;
      if(self.isGet()){
        self.session('userInfo', '');
        self.cookie(AUTH_ID, '',  {
            domain: "",
            path: "/",
            httponly: true,
            timeout: 0
        });
        self.redirect('/');
      }
    },

    signinAction: function(){
      var self = this;
      if(self.isGet()){

      }else if(self.isPost()){
        var data = self.post();
        if(!data.username || !data.password){
          return self.error("请输入正确的用户名和密码")
        }
        Service.createUser(data).then(function(content){
          if(isNumber(content)){
            if(content == -1){
              throw new Error("用户已经存在！")
            }else if(content == -2){
              throw new Error("系统异常，请稍后再试！")
            }else{
              self.session('userInfo',extend({},data,{id:content}))
              return self.success(content);
            }
          }else{
            throw new Error("系统异常，请稍后再试！")
          }
        }).catch(function(err){
          return self.error(err.message || "系统异常，请稍后再试！")
        })
      }
    },

    loginAction: function(){
      var self = this;
      if(self.isGet()){

      }else if(self.isPost()){
        var data = self.post();
        if(!data.username || !data.password){
          return self.err("请输入正确的用户名和密码")
        }
        Service.loginUser(data).then(function(content){
          if(isNumber(content)){
            if(content == -1){
              throw new Error("没有找到该用户！")
            }else if(content == -2){
              throw new Error("用户名或者密码错误！")
            }else{
              if(data.remember == 1){
                self.cookie(AUTH_ID, encrypt(data.username + '\t' + content), {
                    domain: "",
                    path: "/",
                    httponly: true,
                    timeout: 60 * 60 * 24 * 30
                })
              }
              self.session('userInfo',extend({},data,{id:content}))
              return self.success();
            }
          }else{
            throw new Error("系统异常，请稍后再试！")
          }
        }).catch(function(err){
          self.error(err.message || "系统异常，请稍后再试！");
        })
      }
    },

    checkemailAction: function(){
      var self = this;
      Service.checkEmail({"username" : this.param('username')}).then(function(content){
        if(content == 0){
          return self.success({num : content})
        }else if(content == 1){
          return self.success({num : content , msg : "用户已经存在！"})
        }
      }).catch(function(err){
        self.error(err);
      })
    },

    forgetAction: function(){
      var self = this;
      if(self.isGet()){
        self.assign({
          title : "忘记密码",
          section : 'user',
          userInfo : self.userInfo
        })
        return self.display()
      }else if(self.isPost()){
        var data = self.post();
        self.session('captchacode').then(function(res){
          if(data.verifycode == res){
            Service.sendEmail({
              email: data.email,
              subject : "找回密码",
              message : "http://www.nebulafe.com/user/reset/?verify=" + encrypt(data.email)
            })
            return self.success();
          }else{
            self.error("验证码错误！");
          }
        })
      }
    },

    seeAction: function(){
      var self = this;
      if(self.isGet()){
        var user_id = self.get('id');
        if(!user_id){
          return self.redirect("/");
        }
        var value = self.userInfo;
        if (!isEmpty(value)) {
          if(value.id == user_id){
            return Service.getUserById({id:user_id}).then(function(content){
              self.assign({
                title : "查看用户",
                section : 'user',
                userInfo : content[0]
              })
              return self.display()
            }).catch(function(err){

            })
          }else{
            self.session('userInfo', '');
            self.redirect('/');
          }
        }else{
          self.redirect('/');
        }
      }
    },

    resetAction: function(){
      var self = this;
      if(self.isGet()){
        var id = self.get('verify');
        if(!id){
          self.redirect("/")
        }else{
          try{
            var email = decrypt(id);
            if(!isEmail(email)){
              self.redirect("/")
            }
            self.assign({
              title : "重置密码",
              section : 'user',
              userInfo : self.userInfo,
              email: email
            });
            self.display()
          }catch(e){
            return self.redirect("/")
          }
        }
      }else if(self.isPost()){
        var data = self.post();
        Service.resetPwd(data).then(function(res){
          self.success(res)
        }).catch(function(e){
          self.error("系统异常，请稍后再试！");
        })
      }
    },

    getcodeAction: function(){
      var self = this;
      var captchacode = parseInt(Math.random()*9000+1000);
      self.session('captchacode', captchacode);
      var p = new captchapng(70,38,captchacode);
      p.color(0, 12, 0, 0);
      p.color(80, 80, 200, 255);

      var img = p.getBase64();
      var imgbase64 = new Buffer(img,'base64');
      self.header({
          'Content-Type': 'image/png'
      })
      self.end(imgbase64);
    },

    verifyAction : function(){
      var self = this;
      if(self.isGet()){
        self.assign({
          title : "验证邮箱",
          section : 'user',
          userInfo : self.userInfo
        })
        return self.display()
      }else if(self.isPost()){
        var data = self.post();
        self.session('captchacode').then(function(res){
          if(data.verifycode == res){
            Service.sendEmail({
              email: data.email,
              subject : "验证邮箱",
              message : "http://www.nebulafe.com/user/activate/?verify=" + encrypt(data.email)
            })
            return self.success();
          }else{
            self.error("验证码错误！");
          }
        })
      }
    },

    activateAction : function(){
      var self = this;
      if(self.isGet()){
        var id = self.get('verify');
        if(!id){
          self.redirect("/")
        }else{
          try{
            var email = decrypt(id);
            if(!isEmail(email)){
              return self.redirect("/")
            }
            Service.getUserById({"username" : email}).then(function(content){
              if(content && content[0]){
                Service.setUserStatus({
                  "id": content[0].id,
                  "activate_email" : true
                })
                return self.redirect('/')
              }
            })
          }catch(e){
            return self.redirect("/")
          }
        }
      }
    }

  };
})
<commit_msg>add files by wangpengfei<commit_after>/**
 * controller
 * @return
 */
module.exports = Controller("Home/BaseController", function(){
  "use strict";
  var Service = require("../../Service/Service");
  var captchapng = require('captchapng');

  return {
    updateAction: function(){
      var self = this;
      if(self.isGet()){
        return self.redirect("/");
      }else if(self.isPost()){
        var user_id = self.post('id');
        var _user_id = self.userInfo.id;
        if (_user_id) {
          if(_user_id == user_id){
            return Service.updateUserById(self.post()).then(function(content){
              if(content == 0){
                return self.success()
              }else if(content == -1){
                throw new Error('没有找到该用户！')
              }
            }).catch(function(err){
              return self.error(err.message || "系统异常，请稍后再试！")
            })
          }else{
            self.session('userInfo', '');
            self.redirect('/');
          }
        }else{
          self.redirect('/');
        }
      }
    },

    logoutAction: function() {
      var self = this;
      if(self.isGet()){
        self.session('userInfo', '');
        self.cookie(AUTH_ID, '',  {
            domain: "",
            path: "/",
            httponly: true,
            timeout: 0
        });
        self.redirect('/');
      }
    },

    signinAction: function(){
      var self = this;
      if(self.isGet()){

      }else if(self.isPost()){
        var data = self.post();
        if(!data.username || !data.password){
          return self.error("请输入正确的用户名和密码")
        }
        Service.createUser(data).then(function(content){
          if(isNumber(content)){
            if(content == -1){
              throw new Error("用户已经存在！")
            }else if(content == -2){
              throw new Error("系统异常，请稍后再试！")
            }else{
              self.session('userInfo',extend({},data,{id:content}))
              return self.success(content);
            }
          }else{
            throw new Error("系统异常，请稍后再试！")
          }
        }).catch(function(err){
          return self.error(err.message || "系统异常，请稍后再试！")
        })
      }
    },

    loginAction: function(){
      var self = this;
      if(self.isGet()){

      }else if(self.isPost()){
        var data = self.post();
        if(!data.username || !data.password){
          return self.err("请输入正确的用户名和密码")
        }
        Service.loginUser(data).then(function(content){
          if(isNumber(content)){
            if(content == -1){
              throw new Error("没有找到该用户！")
            }else if(content == -2){
              throw new Error("用户名或者密码错误！")
            }else{
              if(data.remember == 1){
                self.cookie(AUTH_ID, encrypt(data.username + '\t' + content), {
                    domain: "",
                    path: "/",
                    httponly: true,
                    timeout: 60 * 60 * 24 * 30
                })
              }
              self.session('userInfo',extend({},data,{id:content}))
              return self.success();
            }
          }else{
            throw new Error("系统异常，请稍后再试！")
          }
        }).catch(function(err){
          self.error(err.message || "系统异常，请稍后再试！");
        })
      }
    },

    checkemailAction: function(){
      var self = this;
      Service.checkEmail({"username" : this.param('username')}).then(function(content){
        if(content == 0){
          return self.success({num : content})
        }else if(content == 1){
          return self.success({num : content , msg : "用户已经存在！"})
        }
      }).catch(function(err){
        self.error(err);
      })
    },

    forgetAction: function(){
      var self = this;
      if(self.isGet()){
        self.assign({
          title : "忘记密码",
          section : 'user',
          userInfo : self.userInfo
        })
        return self.display()
      }else if(self.isPost()){
        var data = self.post();
        self.session('captchacode').then(function(res){
          if(data.verifycode == res){
            Service.sendEmail({
              email: data.email,
              subject : "找回密码",
              message : "http://www.nebulafe.com/user/reset/?verify=" + encrypt(data.email)
            })
            return self.success();
          }else{
            self.error("验证码错误！");
          }
        })
      }
    },

    seeAction: function(){
      var self = this;
      if(self.isGet()){
        var user_id = self.get('id');
        if(!user_id){
          return self.redirect("/");
        }
        var value = self.userInfo;
        if (!isEmpty(value)) {
          if(value.id == user_id){
            return Service.getUserById({id:user_id}).then(function(content){
              self.assign({
                title : "查看用户",
                section : 'user',
                userInfo : content[0]
              })
              return self.display()
            }).catch(function(err){

            })
          }else{
            self.session('userInfo', '');
            self.redirect('/');
          }
        }else{
          self.redirect('/');
        }
      }
    },

    resetAction: function(){
      var self = this;
      if(self.isGet()){
        var id = self.get('verify');
        if(!id){
          self.redirect("/")
        }else{
          try{
            var email = decrypt(id);
            if(!isEmail(email)){
              self.redirect("/")
            }
            self.assign({
              title : "重置密码",
              section : 'user',
              userInfo : self.userInfo,
              email: email
            });
            self.display()
          }catch(e){
            return self.redirect("/")
          }
        }
      }else if(self.isPost()){
        var data = self.post();
        Service.resetPwd(data).then(function(res){
          self.success(res)
        }).catch(function(e){
          self.error("系统异常，请稍后再试！");
        })
      }
    },

    getcodeAction: function(){
      var self = this;
      var captchacode = parseInt(Math.random()*9000+1000);
      self.session('captchacode', captchacode);
      var p = new captchapng(70,38,captchacode);
      p.color(0, 12, 0, 0);
      p.color(80, 80, 200, 255);

      var img = p.getBase64();
      var imgbase64 = new Buffer(img,'base64');
      self.header({
          'Content-Type': 'image/png'
      })
      self.end(imgbase64);
    },

    verifyAction : function(){
      var self = this;
      if(self.isGet()){
        self.assign({
          title : "验证邮箱",
          section : 'user',
          userInfo : self.userInfo
        })
        return self.display()
      }else if(self.isPost()){
        var data = self.post();
        self.session('captchacode').then(function(res){
          if(data.verifycode == res){
            Service.sendEmail({
              email: data.email,
              subject : "验证邮箱",
              message : "http://www.nebulafe.com/user/activate/?verify=" + encrypt(data.email)
            })
            return self.success();
          }else{
            self.error("验证码错误！");
          }
        })
      }
    },

    activateAction : function(){
      var self = this;
      if(self.isGet()){
        var id = self.get('verify');
        if(!id){
          self.redirect("/")
        }else{
          try{
            var email = decrypt(id);
            if(!isEmail(email)){
              return self.redirect("/")
            }
            Service.getUserById({"username" : email}).then(function(content){
              if(content && content[0]){
                Service.setUserStatus({
                  "id": content[0].id,
                  "activate_email" : true
                })
                return self.redirect('/')
              }
            })
          }catch(e){
            return self.redirect("/")
          }
        }
      }
    }

  };
})
<|endoftext|>


<commit_before>module.exports = function(ctrl) {
  var s = '';
  ctrl.analyse.tree.forEach(function(node, i) {
    if (i === 0) return;
    if (i > ctrl.vm.path[0].ply) return;
    console.log(node);
    if (i % 2 === 1) s += ((i + 1) / 2) + '. '
    else s += '';
    s += node.san + ' ';
  });
  return s;
};
<commit_msg>fixes<commit_after>module.exports = function(ctrl) {
  var s = '';
  ctrl.analyse.tree.forEach(function(node, i) {
    if (i === 0) return;
    if (i > ctrl.vm.path[0].ply) return;
    if (i % 2 === 1) s += ((i + 1) / 2) + '. '
    else s += '';
    s += node.san + ' ';
  });
  return s.trim();
};
<|endoftext|>


<commit_before>/**
 * @module core/migrations/migrations
 * @flow
 */

const path = require('path')

const metadata = require('../metadata')
const { SCHEMA_INITIAL_VERSION } = require('./constants')

/*::
import type { SavedMetadata } from '../metadata'
import type { SchemaVersion } from './constants'
import type { InjectedDependencies } from './constants'

export type Migration = {
  baseSchemaVersion: SchemaVersion,
  targetSchemaVersion: SchemaVersion,
  description: string,
  affectedDocs: (SavedMetadata[]) => SavedMetadata[],
  run: (SavedMetadata[], InjectedDependencies) => Promise<SavedMetadata[]>
}
*/

module.exports = ([
  {
    baseSchemaVersion: SCHEMA_INITIAL_VERSION,
    targetSchemaVersion: 1,
    description: 'Adding sides.target with value of _rev',
    affectedDocs: (docs /*: SavedMetadata[] */) /*: SavedMetadata[] */ => {
      return docs.filter(doc => doc.sides == null || doc.sides.target == null)
    },
    run: (docs /*: SavedMetadata[] */) /*: Promise<SavedMetadata[]> */ => {
      return Promise.resolve(
        docs.map(doc => {
          doc.sides = doc.sides || {}
          doc.sides.target = metadata.extractRevNumber(doc)
          return doc
        })
      )
    }
  },
  {
    baseSchemaVersion: 1,
    targetSchemaVersion: 2,
    description: 'Removing overwrite attribute of synced documents',
    affectedDocs: (docs /*: SavedMetadata[] */) /*: SavedMetadata[] */ => {
      return docs.filter(
        doc =>
          doc.overwrite &&
          doc.sides &&
          doc.sides.target === doc.sides.local &&
          doc.sides.target === doc.sides.remote
      )
    },
    run: (docs /*: SavedMetadata[] */) /*: Promise<SavedMetadata[]> */ => {
      return Promise.resolve(
        docs.map(doc => {
          if (doc.overwrite) delete doc.overwrite
          return doc
        })
      )
    }
  },
  {
    baseSchemaVersion: 2,
    targetSchemaVersion: 3,
    description: 'Marking Cozy Notes for refetch to avoid conflicts',
    affectedDocs: (docs /*: SavedMetadata[] */) /*: SavedMetadata[] */ => {
      return docs.filter(
        doc =>
          doc.mime === 'text/vnd.cozy.note+markdown' &&
          doc.metadata &&
          doc.metadata.content &&
          doc.sides &&
          doc.sides.local &&
          doc.sides.remote
      )
    },
    run: (docs /*: SavedMetadata[] */) /*: Promise<SavedMetadata[]> */ => {
      return Promise.resolve(
        docs.map(doc => {
          if (doc.sides && doc.sides.local && doc.sides.remote) {
            doc.sides.target =
              Math.max(doc.sides.target, doc.sides.local, doc.sides.remote) + 1
            doc.sides.remote = doc.sides.target
          }
          return doc
        })
      )
    }
  },
  {
    baseSchemaVersion: 3,
    targetSchemaVersion: 4,
    description: 'Generating files local Metadata info with current Metadata',
    affectedDocs: (docs /*: SavedMetadata[] */) /*: SavedMetadata[] */ => {
      return docs.filter(doc => doc.docType === 'file')
    },
    run: (docs /*: SavedMetadata[] */) /*: Promise<SavedMetadata[]> */ => {
      return Promise.resolve(
        docs.map(doc => {
          // $FlowFixMe path was not present when this migration was created
          doc.local = {
            md5sum: doc.md5sum,
            class: doc.class,
            docType: 'file',
            executable: doc.executable,
            updated_at: doc.updated_at,
            mime: doc.mime,
            size: doc.size,
            ino: doc.ino,
            fileid: doc.fileid
          }
          return doc
        })
      )
    }
  },
  {
    baseSchemaVersion: 4,
    targetSchemaVersion: 5,
    description: 'Removing moveFrom attribute of synced documents',
    affectedDocs: (docs /*: SavedMetadata[] */) /*: SavedMetadata[] */ => {
      return docs.filter(
        doc =>
          doc.moveFrom &&
          doc.sides &&
          doc.sides.target === doc.sides.local &&
          doc.sides.target === doc.sides.remote
      )
    },
    run: (docs /*: SavedMetadata[] */) /*: Promise<SavedMetadata[]> */ => {
      return Promise.resolve(
        docs.map(doc => {
          if (doc.moveFrom) delete doc.moveFrom
          return doc
        })
      )
    }
  },
  {
    baseSchemaVersion: 5,
    targetSchemaVersion: 6,
    description: 'Generating folders local Metadata info with current Metadata',
    affectedDocs: (docs /*: SavedMetadata[] */) /*: SavedMetadata[] */ => {
      return docs.filter(doc => doc.docType === 'folders')
    },
    run: (docs /*: SavedMetadata[] */) /*: Promise<SavedMetadata[]> */ => {
      return Promise.resolve(
        docs.map(doc => {
          // $FlowFixMe path was not present when this migration was created
          doc.local = {
            docType: 'folder',
            updated_at: doc.updated_at,
            ino: doc.ino,
            fileid: doc.fileid
          }
          return doc
        })
      )
    }
  },
  {
    baseSchemaVersion: 6,
    targetSchemaVersion: 7,
    description: 'Add path to local and remote metadata',
    affectedDocs: (docs /*: SavedMetadata[] */) /*: SavedMetadata[] */ => {
      return docs.filter(doc => doc.local != null || doc.remote != null)
    },
    run: (docs /*: SavedMetadata[] */) /*: Promise<SavedMetadata[]> */ => {
      return Promise.resolve(
        docs.map(doc => {
          if (doc.local) doc.local.path = doc.path
          if (doc.remote)
            doc.remote.path = '/' + path.posix.join(...doc.path.split(path.sep))
          return doc
        })
      )
    }
  },
  {
    baseSchemaVersion: 7,
    targetSchemaVersion: 8,
    description: 'Set all files executable attribute',
    affectedDocs: (docs /*: SavedMetadata[] */) /*: SavedMetadata[] */ => {
      return docs.filter(
        doc => doc.docType === 'file' && doc.executable == null
      )
    },
    run: (docs /*: SavedMetadata[] */) /*: Promise<SavedMetadata[]> */ => {
      return Promise.resolve(
        docs.map(doc => {
          doc.executable = false
          if (doc.local && doc.local.executable == null) {
            doc.local.executable = false
          }
          return doc
        })
      )
    }
  },
  {
    baseSchemaVersion: 8,
    targetSchemaVersion: 9,
    description: 'Default tags attribute to an empty Array',
    affectedDocs: (docs /*: SavedMetadata[] */) /*: SavedMetadata[] */ => {
      return docs.filter(doc => doc.docType != null && !doc.tags)
    },
    run: (docs /*: SavedMetadata[] */) /*: Promise<SavedMetadata[]> */ => {
      return Promise.resolve(
        docs.map(doc => {
          doc.tags = []
          return doc
        })
      )
    }
  },
  {
    baseSchemaVersion: 9,
    targetSchemaVersion: 10,
    description: 'Cleanup corrupted record sides',
    affectedDocs: (docs /*: SavedMetadata[] */) /*: SavedMetadata[] */ => {
      return docs.filter(
        doc =>
          doc.sides &&
          ((doc.sides.local && !doc.local) || (doc.sides.remote && !doc.remote))
      )
    },
    run: (docs /*: SavedMetadata[] */) /*: Promise<SavedMetadata[]> */ => {
      return Promise.resolve(
        docs.map(doc => {
          if (doc.sides.local && !doc.local) {
            // Remove local side when no local attribute exists
            delete doc.sides.local
          }
          if (doc.sides.remote && !doc.remote) {
            // Remove remote side when no remote attribute exists
            delete doc.sides.remote
          }
          if (!doc.sides.local && !doc.sides.remote) {
            // Erase record is no sides are remaining
            doc._deleted = true
          }
          // Remove errors, in case this would result in a new Sync attempt
          delete doc.errors
          return doc
        })
      )
    }
  },
  {
    baseSchemaVersion: 10,
    targetSchemaVersion: 11,
    description: 'Add type attribute to pathMaxBytes incompatibilities',
    affectedDocs: (docs /*: SavedMetadata[] */) /*: SavedMetadata[] */ => {
      return docs.filter(
        doc =>
          doc.incompatibilities &&
          doc.incompatibilities.find(issue => issue.type == null) != null
      )
    },
    run: (docs /*: SavedMetadata[] */) /*: Promise<SavedMetadata[]> */ => {
      return Promise.resolve(
        docs.map(doc => {
          if (doc.incompatibilities) {
            const issue = doc.incompatibilities.find(
              issue => issue.type == null
            )
            if (issue) {
              // $FlowFixMe `type` is not set so it can't be another value
              issue.type = 'pathMaxBytes'
            }
          }
          return doc
        })
      )
    }
  },
  {
    baseSchemaVersion: 11,
    targetSchemaVersion: 12,
    description: 'Remove unnecessary Windows path length incompatibilities',
    affectedDocs: (docs /*: SavedMetadata[] */) /*: SavedMetadata[] */ => {
      return docs.filter(
        doc =>
          doc.incompatibilities &&
          doc.incompatibilities.find(
            issue =>
              issue.platform === 'win32' &&
              issue.type === 'pathMaxBytes' &&
              issue.pathBytes <= 32766
          ) != null
      )
    },
    run: (docs /*: SavedMetadata[] */) /*: Promise<SavedMetadata[]> */ => {
      return Promise.resolve(
        docs.map(doc => {
          if (doc.incompatibilities) {
            if (doc.incompatibilities.length === 1) {
              // Sync expects `incompatibilities` to be missing when there aren't
              // any so if we're about to delete the last one, we remove the
              // attribute altogether.
              delete doc.incompatibilities
            } else {
              const { incompatibilities } = doc
              const index = incompatibilities.findIndex(
                issue =>
                  issue.platform === 'win32' &&
                  issue.type === 'pathMaxBytes' &&
                  issue.pathBytes < 32766
              )
              incompatibilities.splice(index, 1)
            }
          }
          return doc
        })
      )
    }
  },
  {
    baseSchemaVersion: 12,
    targetSchemaVersion: 13,
    description: 'Merge trashed and deleted attributes into trashed',
    affectedDocs: (docs /*: SavedMetadata[] */) /*: SavedMetadata[] */ => {
      // $FlowFixMe `deleted` has been removed from Metadata thus this migration
      return docs.filter(doc => doc.deleted != null)
    },
    run: (docs /*: SavedMetadata[] */) /*: Promise<SavedMetadata[]> */ => {
      return Promise.resolve(
        docs.map(doc => {
          // $FlowFixMe `deleted` has been removed from Metadata
          if (doc.deleted) {
            doc.trashed = true
          }
          // $FlowFixMe `deleted` has been removed from Metadata
          delete doc.deleted
          return doc
        })
      )
    }
  },
  {
    baseSchemaVersion: 13,
    targetSchemaVersion: 14,
    description: 'Refetch remote revision of all directories',
    affectedDocs: (docs /*: SavedMetadata[] */) /*: SavedMetadata[] */ => {
      // $FlowFixMe `deleted` has been removed from Metadata thus this migration
      return docs.filter(doc => doc.docType === 'folder' && doc.remote != null)
    },
    run: (
      docs /*: SavedMetadata[] */,
      { remote } /*: InjectedDependencies */
    ) /*: Promise<SavedMetadata[]> */ => {
      return Promise.all(
        docs.map(async doc => {
          const remoteDir = await remote.remoteCozy.findDir(doc.remote._id)

          if (remoteDir != null) {
            if (
              remoteDir._rev !== doc.remote._rev &&
              metadata.equivalentRemote(
                metadata.serializableRemote(remoteDir),
                doc.remote
              )
            ) {
              doc.remote._rev = remoteDir._rev
            }

            const { moveFrom } = doc
            if (
              moveFrom != null &&
              moveFrom.remote != null &&
              remoteDir._rev !== moveFrom.remote._rev &&
              metadata.equivalentRemote(
                metadata.serializableRemote(remoteDir),
                moveFrom.remote
              )
            ) {
              moveFrom.remote._rev = remoteDir._rev
            }
          }

          const { overwrite } = doc
          if (overwrite != null && overwrite.remote != null) {
            const remoteOverwritten = await remote.remoteCozy.findDir(
              overwrite.remote._id
            )

            if (
              remoteOverwritten != null &&
              remoteOverwritten._rev !== overwrite.remote._rev &&
              metadata.equivalentRemote(
                metadata.serializableRemote(remoteOverwritten),
                overwrite.remote
              )
            ) {
              overwrite.remote._rev = remoteOverwritten._rev
            }
          }

          return doc
        })
      )
    }
  }
] /*: Migration[] */)
<commit_msg>core/migrations: Limit concurrent network requests<commit_after>/**
 * @module core/migrations/migrations
 * @flow
 */

const path = require('path')
const { Promise } = require('bluebird')

const metadata = require('../metadata')
const { SCHEMA_INITIAL_VERSION } = require('./constants')

/*::
import type { SavedMetadata } from '../metadata'
import type { SchemaVersion } from './constants'
import type { InjectedDependencies } from './constants'

export type Migration = {
  baseSchemaVersion: SchemaVersion,
  targetSchemaVersion: SchemaVersion,
  description: string,
  affectedDocs: (SavedMetadata[]) => SavedMetadata[],
  run: (SavedMetadata[], InjectedDependencies) => Promise<SavedMetadata[]>
}
*/

module.exports = ([
  {
    baseSchemaVersion: SCHEMA_INITIAL_VERSION,
    targetSchemaVersion: 1,
    description: 'Adding sides.target with value of _rev',
    affectedDocs: (docs /*: SavedMetadata[] */) /*: SavedMetadata[] */ => {
      return docs.filter(doc => doc.sides == null || doc.sides.target == null)
    },
    run: (docs /*: SavedMetadata[] */) /*: Promise<SavedMetadata[]> */ => {
      return Promise.resolve(
        docs.map(doc => {
          doc.sides = doc.sides || {}
          doc.sides.target = metadata.extractRevNumber(doc)
          return doc
        })
      )
    }
  },
  {
    baseSchemaVersion: 1,
    targetSchemaVersion: 2,
    description: 'Removing overwrite attribute of synced documents',
    affectedDocs: (docs /*: SavedMetadata[] */) /*: SavedMetadata[] */ => {
      return docs.filter(
        doc =>
          doc.overwrite &&
          doc.sides &&
          doc.sides.target === doc.sides.local &&
          doc.sides.target === doc.sides.remote
      )
    },
    run: (docs /*: SavedMetadata[] */) /*: Promise<SavedMetadata[]> */ => {
      return Promise.resolve(
        docs.map(doc => {
          if (doc.overwrite) delete doc.overwrite
          return doc
        })
      )
    }
  },
  {
    baseSchemaVersion: 2,
    targetSchemaVersion: 3,
    description: 'Marking Cozy Notes for refetch to avoid conflicts',
    affectedDocs: (docs /*: SavedMetadata[] */) /*: SavedMetadata[] */ => {
      return docs.filter(
        doc =>
          doc.mime === 'text/vnd.cozy.note+markdown' &&
          doc.metadata &&
          doc.metadata.content &&
          doc.sides &&
          doc.sides.local &&
          doc.sides.remote
      )
    },
    run: (docs /*: SavedMetadata[] */) /*: Promise<SavedMetadata[]> */ => {
      return Promise.resolve(
        docs.map(doc => {
          if (doc.sides && doc.sides.local && doc.sides.remote) {
            doc.sides.target =
              Math.max(doc.sides.target, doc.sides.local, doc.sides.remote) + 1
            doc.sides.remote = doc.sides.target
          }
          return doc
        })
      )
    }
  },
  {
    baseSchemaVersion: 3,
    targetSchemaVersion: 4,
    description: 'Generating files local Metadata info with current Metadata',
    affectedDocs: (docs /*: SavedMetadata[] */) /*: SavedMetadata[] */ => {
      return docs.filter(doc => doc.docType === 'file')
    },
    run: (docs /*: SavedMetadata[] */) /*: Promise<SavedMetadata[]> */ => {
      return Promise.resolve(
        docs.map(doc => {
          // $FlowFixMe path was not present when this migration was created
          doc.local = {
            md5sum: doc.md5sum,
            class: doc.class,
            docType: 'file',
            executable: doc.executable,
            updated_at: doc.updated_at,
            mime: doc.mime,
            size: doc.size,
            ino: doc.ino,
            fileid: doc.fileid
          }
          return doc
        })
      )
    }
  },
  {
    baseSchemaVersion: 4,
    targetSchemaVersion: 5,
    description: 'Removing moveFrom attribute of synced documents',
    affectedDocs: (docs /*: SavedMetadata[] */) /*: SavedMetadata[] */ => {
      return docs.filter(
        doc =>
          doc.moveFrom &&
          doc.sides &&
          doc.sides.target === doc.sides.local &&
          doc.sides.target === doc.sides.remote
      )
    },
    run: (docs /*: SavedMetadata[] */) /*: Promise<SavedMetadata[]> */ => {
      return Promise.resolve(
        docs.map(doc => {
          if (doc.moveFrom) delete doc.moveFrom
          return doc
        })
      )
    }
  },
  {
    baseSchemaVersion: 5,
    targetSchemaVersion: 6,
    description: 'Generating folders local Metadata info with current Metadata',
    affectedDocs: (docs /*: SavedMetadata[] */) /*: SavedMetadata[] */ => {
      return docs.filter(doc => doc.docType === 'folders')
    },
    run: (docs /*: SavedMetadata[] */) /*: Promise<SavedMetadata[]> */ => {
      return Promise.resolve(
        docs.map(doc => {
          // $FlowFixMe path was not present when this migration was created
          doc.local = {
            docType: 'folder',
            updated_at: doc.updated_at,
            ino: doc.ino,
            fileid: doc.fileid
          }
          return doc
        })
      )
    }
  },
  {
    baseSchemaVersion: 6,
    targetSchemaVersion: 7,
    description: 'Add path to local and remote metadata',
    affectedDocs: (docs /*: SavedMetadata[] */) /*: SavedMetadata[] */ => {
      return docs.filter(doc => doc.local != null || doc.remote != null)
    },
    run: (docs /*: SavedMetadata[] */) /*: Promise<SavedMetadata[]> */ => {
      return Promise.resolve(
        docs.map(doc => {
          if (doc.local) doc.local.path = doc.path
          if (doc.remote)
            doc.remote.path = '/' + path.posix.join(...doc.path.split(path.sep))
          return doc
        })
      )
    }
  },
  {
    baseSchemaVersion: 7,
    targetSchemaVersion: 8,
    description: 'Set all files executable attribute',
    affectedDocs: (docs /*: SavedMetadata[] */) /*: SavedMetadata[] */ => {
      return docs.filter(
        doc => doc.docType === 'file' && doc.executable == null
      )
    },
    run: (docs /*: SavedMetadata[] */) /*: Promise<SavedMetadata[]> */ => {
      return Promise.resolve(
        docs.map(doc => {
          doc.executable = false
          if (doc.local && doc.local.executable == null) {
            doc.local.executable = false
          }
          return doc
        })
      )
    }
  },
  {
    baseSchemaVersion: 8,
    targetSchemaVersion: 9,
    description: 'Default tags attribute to an empty Array',
    affectedDocs: (docs /*: SavedMetadata[] */) /*: SavedMetadata[] */ => {
      return docs.filter(doc => doc.docType != null && !doc.tags)
    },
    run: (docs /*: SavedMetadata[] */) /*: Promise<SavedMetadata[]> */ => {
      return Promise.resolve(
        docs.map(doc => {
          doc.tags = []
          return doc
        })
      )
    }
  },
  {
    baseSchemaVersion: 9,
    targetSchemaVersion: 10,
    description: 'Cleanup corrupted record sides',
    affectedDocs: (docs /*: SavedMetadata[] */) /*: SavedMetadata[] */ => {
      return docs.filter(
        doc =>
          doc.sides &&
          ((doc.sides.local && !doc.local) || (doc.sides.remote && !doc.remote))
      )
    },
    run: (docs /*: SavedMetadata[] */) /*: Promise<SavedMetadata[]> */ => {
      return Promise.resolve(
        docs.map(doc => {
          if (doc.sides.local && !doc.local) {
            // Remove local side when no local attribute exists
            delete doc.sides.local
          }
          if (doc.sides.remote && !doc.remote) {
            // Remove remote side when no remote attribute exists
            delete doc.sides.remote
          }
          if (!doc.sides.local && !doc.sides.remote) {
            // Erase record is no sides are remaining
            doc._deleted = true
          }
          // Remove errors, in case this would result in a new Sync attempt
          delete doc.errors
          return doc
        })
      )
    }
  },
  {
    baseSchemaVersion: 10,
    targetSchemaVersion: 11,
    description: 'Add type attribute to pathMaxBytes incompatibilities',
    affectedDocs: (docs /*: SavedMetadata[] */) /*: SavedMetadata[] */ => {
      return docs.filter(
        doc =>
          doc.incompatibilities &&
          doc.incompatibilities.find(issue => issue.type == null) != null
      )
    },
    run: (docs /*: SavedMetadata[] */) /*: Promise<SavedMetadata[]> */ => {
      return Promise.resolve(
        docs.map(doc => {
          if (doc.incompatibilities) {
            const issue = doc.incompatibilities.find(
              issue => issue.type == null
            )
            if (issue) {
              // $FlowFixMe `type` is not set so it can't be another value
              issue.type = 'pathMaxBytes'
            }
          }
          return doc
        })
      )
    }
  },
  {
    baseSchemaVersion: 11,
    targetSchemaVersion: 12,
    description: 'Remove unnecessary Windows path length incompatibilities',
    affectedDocs: (docs /*: SavedMetadata[] */) /*: SavedMetadata[] */ => {
      return docs.filter(
        doc =>
          doc.incompatibilities &&
          doc.incompatibilities.find(
            issue =>
              issue.platform === 'win32' &&
              issue.type === 'pathMaxBytes' &&
              issue.pathBytes <= 32766
          ) != null
      )
    },
    run: (docs /*: SavedMetadata[] */) /*: Promise<SavedMetadata[]> */ => {
      return Promise.resolve(
        docs.map(doc => {
          if (doc.incompatibilities) {
            if (doc.incompatibilities.length === 1) {
              // Sync expects `incompatibilities` to be missing when there aren't
              // any so if we're about to delete the last one, we remove the
              // attribute altogether.
              delete doc.incompatibilities
            } else {
              const { incompatibilities } = doc
              const index = incompatibilities.findIndex(
                issue =>
                  issue.platform === 'win32' &&
                  issue.type === 'pathMaxBytes' &&
                  issue.pathBytes < 32766
              )
              incompatibilities.splice(index, 1)
            }
          }
          return doc
        })
      )
    }
  },
  {
    baseSchemaVersion: 12,
    targetSchemaVersion: 13,
    description: 'Merge trashed and deleted attributes into trashed',
    affectedDocs: (docs /*: SavedMetadata[] */) /*: SavedMetadata[] */ => {
      // $FlowFixMe `deleted` has been removed from Metadata thus this migration
      return docs.filter(doc => doc.deleted != null)
    },
    run: (docs /*: SavedMetadata[] */) /*: Promise<SavedMetadata[]> */ => {
      return Promise.resolve(
        docs.map(doc => {
          // $FlowFixMe `deleted` has been removed from Metadata
          if (doc.deleted) {
            doc.trashed = true
          }
          // $FlowFixMe `deleted` has been removed from Metadata
          delete doc.deleted
          return doc
        })
      )
    }
  },
  {
    baseSchemaVersion: 13,
    targetSchemaVersion: 14,
    description: 'Refetch remote revision of all directories',
    affectedDocs: (docs /*: SavedMetadata[] */) /*: SavedMetadata[] */ => {
      // $FlowFixMe `deleted` has been removed from Metadata thus this migration
      return docs.filter(doc => doc.docType === 'folder' && doc.remote != null)
    },
    run: (
      docs /*: SavedMetadata[] */,
      { remote } /*: InjectedDependencies */
    ) /*: Promise<SavedMetadata[]> */ => {
      return Promise.map(
        docs,
        async doc => {
          const remoteDir = await remote.remoteCozy.findDir(doc.remote._id)

          if (remoteDir != null) {
            if (
              remoteDir._rev !== doc.remote._rev &&
              metadata.equivalentRemote(
                metadata.serializableRemote(remoteDir),
                doc.remote
              )
            ) {
              doc.remote._rev = remoteDir._rev
            }

            const { moveFrom } = doc
            if (
              moveFrom != null &&
              moveFrom.remote != null &&
              remoteDir._rev !== moveFrom.remote._rev &&
              metadata.equivalentRemote(
                metadata.serializableRemote(remoteDir),
                moveFrom.remote
              )
            ) {
              moveFrom.remote._rev = remoteDir._rev
            }
          }

          const { overwrite } = doc
          if (overwrite != null && overwrite.remote != null) {
            const remoteOverwritten = await remote.remoteCozy.findDir(
              overwrite.remote._id
            )

            if (
              remoteOverwritten != null &&
              remoteOverwritten._rev !== overwrite.remote._rev &&
              metadata.equivalentRemote(
                metadata.serializableRemote(remoteOverwritten),
                overwrite.remote
              )
            ) {
              overwrite.remote._rev = remoteOverwritten._rev
            }
          }

          return doc
        },
        // XXX: Avoid exhausting network resources by limiting the number of
        // concurrent requests.
        { concurrency: 10 }
      )
    }
  }
] /*: Migration[] */)
<|endoftext|>


<commit_before>import _ from 'lodash';
// We have to remove node_modules/react to avoid having multiple copies loaded.
// eslint-disable-next-line import/no-unresolved
import React, { Component, PropTypes } from 'react';
import Pane from '@folio/stripes-components/lib/Pane';
import PaneMenu from '@folio/stripes-components/lib/PaneMenu';
import Button from '@folio/stripes-components/lib/Button';
import KeyValue from '@folio/stripes-components/lib/KeyValue';
import { Row, Col } from 'react-bootstrap';
import TextField from '@folio/stripes-components/lib/TextField';
import MultiColumnList from '@folio/stripes-components/lib/MultiColumnList';
import Icon from '@folio/stripes-components/lib/Icon';
import Layer from '@folio/stripes-components/lib/Layer';
import IfPermission from '@folio/stripes-components/lib/IfPermission';

import UserForm from './UserForm';
import UserPermissions from './UserPermissions';
import UserLoans from './UserLoans';
import LoansHistory from './LoansHistory';

class ViewUser extends Component {

  static propTypes = {
    stripes: PropTypes.shape({
      hasPerm: PropTypes.func.isRequired,
      connect: PropTypes.func.isRequired,
      locale: PropTypes.string.isRequired,
    }).isRequired,
    paneWidth: PropTypes.string.isRequired,
    data: PropTypes.shape({
      user: PropTypes.arrayOf(PropTypes.object),
      patronGroups: PropTypes.arrayOf(PropTypes.object),
    }),
    mutator: React.PropTypes.shape({
      selUser: React.PropTypes.shape({
        PUT: React.PropTypes.func.isRequired,
      }),
    }),
    match: PropTypes.shape({
      path: PropTypes.string.isRequired,
    }).isRequired,
    onClose: PropTypes.func,
    okapi: PropTypes.object,
  };

  static manifest = Object.freeze({
    selUser: {
      type: 'okapi',
      path: 'users/:{userid}',
      clear: false,
    },
    patronGroups: {
      type: 'okapi',
      path: 'groups',
      records: 'usergroups',
    },
  });

  constructor(props) {
    super(props);
    this.state = {
      editUserMode: false,
      viewLoansHistoryMode: false,
    };
    this.onClickEditUser = this.onClickEditUser.bind(this);
    this.onClickCloseEditUser = this.onClickCloseEditUser.bind(this);
    this.connectedUserLoans = props.stripes.connect(UserLoans);
    this.connectedLoansHistory = props.stripes.connect(LoansHistory);
    this.connectedUserPermissions = props.stripes.connect(UserPermissions);
    this.onClickViewLoansHistory = this.onClickViewLoansHistory.bind(this);
    this.onClickCloseLoansHistory = this.onClickCloseLoansHistory.bind(this);
  }

  // EditUser Handlers
  onClickEditUser(e) {
    if (e) e.preventDefault();
    this.setState({
      editUserMode: true,
    });
  }

  onClickCloseEditUser(e) {
    if (e) e.preventDefault();
    this.setState({
      editUserMode: false,
    });
  }

  onClickViewLoansHistory(e) {
    if (e) e.preventDefault();
    this.setState({
      viewLoansHistoryMode: true,
    });
  }

  onClickCloseLoansHistory(e) {
    if (e) e.preventDefault();
    this.setState({
      viewLoansHistoryMode: false,
    });
  }

  update(data) {
    // eslint-disable-next-line no-param-reassign
    if (data.creds) delete data.creds; // not handled on edit (yet at least)
    // eslint-disable-next-line no-param-reassign
    if (data.available_patron_groups) delete data.available_patron_groups;
    this.props.mutator.selUser.PUT(data).then(() => {
      this.onClickCloseEditUser();
    });
  }

  render() {
    const fineHistory = [{ 'Due Date': '11/12/2014', Amount: '34.23', Status: 'Unpaid' }];

    const { data: { selUser, patronGroups }, match: { params: { userid } } } = this.props;

    const detailMenu = (<PaneMenu>
      <IfPermission perm="users.item.put">
        <button onClick={this.onClickEditUser} title="Edit User"><Icon icon="edit" />Edit</button>
      </IfPermission>
    </PaneMenu>);

    if (!selUser || selUser.length === 0 || !userid) return
;

    const user = selUser.find(u => u.id === userid);
    if (!user) return
;
    const userStatus = (_.get(user, ['active'], '') ? 'active' : 'inactive');
    const patronGroupId = _.get(user, ['patronGroup'], '');
    const patronGroup = patronGroups.find(g => g.id === patronGroupId) || { group: '' };

    return (
      <Pane defaultWidth={this.props.paneWidth} paneTitle="User Details" lastMenu={detailMenu} dismissible onClose={this.props.onClose}>
        <Row>
          <Col xs={7} >
            <Row>
              <Col xs={12}>

{_.get(user, ['personal', 'lastName'], '')}, {_.get(user, ['personal', 'firstName'], '')} {_.get(user, ['personal', 'middleName'], '')}

              </Col>
            </Row>
            <Row>
              <Col xs={12}>
                <KeyValue label="User ID" value={_.get(user, ['username'], '')} />
              </Col>
            </Row>

            <Row>
              <Col xs={12}>
                <KeyValue label="Status" value={userStatus} />
              </Col>
            </Row>

            <Row>
              <Col xs={12}>
                <KeyValue label="Email" value={_.get(user, ['personal', 'email'], '')} />
              </Col>
            </Row>

            <Row>
              <Col xs={12}>
                <KeyValue label="Phone" value={_.get(user, ['personal', 'phone'], '')} />
              </Col>
            </Row>

            <Row>
              <Col xs={12}>
                <KeyValue label="Mobile phone" value={_.get(user, ['personal', 'mobilePhone'], '')} />
              </Col>
            </Row>

            <Row>
              <Col xs={12}>
                <KeyValue label="Date of birth" value={(_.get(user, ['personal', 'dateOfBirth'], '')) ? new Date(Date.parse(_.get(user, ['personal', 'dateOfBirth'], ''))).toLocaleDateString(this.props.stripes.locale) : ''} />
              </Col>
            </Row>

            <Row>
              <Col xs={12}>
                <KeyValue label="Patron group" value={patronGroup.desc} />
              </Col>
            </Row>
          </Col>
          <Col xs={5} >
            <Row>
              <Col xs={12}>

              </Col>
            </Row>

            <Row>
              <Col xs={12}>
                <KeyValue label="Date enrolled" value={(_.get(user, ['enrollmentDate'],'')) ? new Date(Date.parse(_.get(user, ['enrollmentDate'], ''))).toLocaleDateString(this.props.stripes.locale) : ''} />
              </Col>
            </Row>
            <Row>
              <Col xs={12}>
                <KeyValue label="Expiration date" value={(_.get(user, ['expirationDate'],'')) ? new Date(Date.parse(_.get(user, ['expirationDate'], ''))).toLocaleDateString(this.props.stripes.locale) : ''} />
              </Col>
            </Row>
            <Row>
              <Col xs={12}>
                <KeyValue label="Bar code" value={_.get(user, ['barcode'], '')} />
              </Col>
            </Row>
            <Row>
              <Col xs={12}>
                <KeyValue label="FOLIO record number" value={_.get(user, ['id'], '')} />
              </Col>
            </Row>
            <Row>
              <Col xs={12}>
                <KeyValue label="External System ID" value={_.get(user, ['externalSystemId'], '')} />
              </Col>
            </Row>
          </Col>
        </Row>

        <Row>
          <Col xs={3}>

Fines

          </Col>
          <Col xs={4} sm={3}>
            <TextField
              rounded
              endControl={<Button buttonStyle="fieldControl"><Icon icon="clearX" /></Button>}
              startControl={<Icon icon="search" />}
              placeholder="Search"
              fullWidth
            />
          </Col>
          <Col xs={5} sm={6}>
            <Button align="end" bottomMargin0 >View Full History</Button>
          </Col>
        </Row>
        <MultiColumnList fullWidth contentData={fineHistory} />

        <IfPermission perm="circulation.loans.collection.get">
          <this.connectedUserLoans onClickViewLoansHistory={this.onClickViewLoansHistory} {...this.props} />
        </IfPermission>
        <IfPermission perm="perms.users.get">
          <this.connectedUserPermissions stripes={this.props.stripes} match={this.props.match} {...this.props} />
        </IfPermission>
        <Layer isOpen={this.state.editUserMode} label="Edit User Dialog">
          <UserForm
            initialValues={_.merge(user, { available_patron_groups: this.props.data.patronGroups })}
            onSubmit={(record) => { this.update(record); }}
            onCancel={this.onClickCloseEditUser}
            okapi={this.props.okapi}
          />
        </Layer>
        <Layer isOpen={this.state.viewLoansHistoryMode} label="Loans History">
          <this.connectedLoansHistory userid={userid} stripes={this.props.stripes} onCancel={this.onClickCloseLoansHistory} />
        </Layer>
      </Pane>
    );
  }
}

export default ViewUser;
<commit_msg>Keep editMode boolean in stripes-core local resource<commit_after>import _ from 'lodash';
// We have to remove node_modules/react to avoid having multiple copies loaded.
// eslint-disable-next-line import/no-unresolved
import React, { Component, PropTypes } from 'react';
import Pane from '@folio/stripes-components/lib/Pane';
import PaneMenu from '@folio/stripes-components/lib/PaneMenu';
import Button from '@folio/stripes-components/lib/Button';
import KeyValue from '@folio/stripes-components/lib/KeyValue';
import { Row, Col } from 'react-bootstrap';
import TextField from '@folio/stripes-components/lib/TextField';
import MultiColumnList from '@folio/stripes-components/lib/MultiColumnList';
import Icon from '@folio/stripes-components/lib/Icon';
import Layer from '@folio/stripes-components/lib/Layer';
import IfPermission from '@folio/stripes-components/lib/IfPermission';

import UserForm from './UserForm';
import UserPermissions from './UserPermissions';
import UserLoans from './UserLoans';
import LoansHistory from './LoansHistory';

class ViewUser extends Component {

  static propTypes = {
    stripes: PropTypes.shape({
      hasPerm: PropTypes.func.isRequired,
      connect: PropTypes.func.isRequired,
      locale: PropTypes.string.isRequired,
    }).isRequired,
    paneWidth: PropTypes.string.isRequired,
    data: PropTypes.shape({
      user: PropTypes.arrayOf(PropTypes.object),
      patronGroups: PropTypes.arrayOf(PropTypes.object),
    }),
    mutator: React.PropTypes.shape({
      selUser: React.PropTypes.shape({
        PUT: React.PropTypes.func.isRequired,
      }),
      editMode: PropTypes.shape({
        replace: PropTypes.func,
      }),
    }),
    match: PropTypes.shape({
      path: PropTypes.string.isRequired,
    }).isRequired,
    onClose: PropTypes.func,
    okapi: PropTypes.object,
  };

  static manifest = Object.freeze({
    editMode: {},
    selUser: {
      type: 'okapi',
      path: 'users/:{userid}',
      clear: false,
    },
    patronGroups: {
      type: 'okapi',
      path: 'groups',
      records: 'usergroups',
    },
  });

  constructor(props) {
    super(props);
    this.state = {
      viewLoansHistoryMode: false,
    };
    this.onClickEditUser = this.onClickEditUser.bind(this);
    this.onClickCloseEditUser = this.onClickCloseEditUser.bind(this);
    this.connectedUserLoans = props.stripes.connect(UserLoans);
    this.connectedLoansHistory = props.stripes.connect(LoansHistory);
    this.connectedUserPermissions = props.stripes.connect(UserPermissions);
    this.onClickViewLoansHistory = this.onClickViewLoansHistory.bind(this);
    this.onClickCloseLoansHistory = this.onClickCloseLoansHistory.bind(this);
  }

  componentWillMount() {
    if (_.isEmpty(this.props.data.editMode)) this.props.mutator.editMode.replace({ mode: false });
  }

  // EditUser Handlers
  onClickEditUser(e) {
    if (e) e.preventDefault();
    this.props.stripes.logger.log('action', 'clicked "edit user"');
    this.props.mutator.editMode.replace({ mode: true });
  }

  onClickCloseEditUser(e) {
    if (e) e.preventDefault();
    this.props.stripes.logger.log('action', 'clicked "close edit user"');
    this.props.mutator.editMode.replace({ mode: false });
  }

  onClickViewLoansHistory(e) {
    if (e) e.preventDefault();
    this.setState({
      viewLoansHistoryMode: true,
    });
  }

  onClickCloseLoansHistory(e) {
    if (e) e.preventDefault();
    this.setState({
      viewLoansHistoryMode: false,
    });
  }

  update(data) {
    // eslint-disable-next-line no-param-reassign
    if (data.creds) delete data.creds; // not handled on edit (yet at least)
    // eslint-disable-next-line no-param-reassign
    if (data.available_patron_groups) delete data.available_patron_groups;
    this.props.mutator.selUser.PUT(data).then(() => {
      this.onClickCloseEditUser();
    });
  }

  render() {
    const fineHistory = [{ 'Due Date': '11/12/2014', Amount: '34.23', Status: 'Unpaid' }];

    const { data: { selUser, patronGroups }, match: { params: { userid } } } = this.props;

    const detailMenu = (<PaneMenu>
      <IfPermission perm="users.item.put">
        <button onClick={this.onClickEditUser} title="Edit User"><Icon icon="edit" />Edit</button>
      </IfPermission>
    </PaneMenu>);

    if (!selUser || selUser.length === 0 || !userid) return
;

    const user = selUser.find(u => u.id === userid);
    if (!user) return
;
    const userStatus = (_.get(user, ['active'], '') ? 'active' : 'inactive');
    const patronGroupId = _.get(user, ['patronGroup'], '');
    const patronGroup = patronGroups.find(g => g.id === patronGroupId) || { group: '' };

    return (
      <Pane defaultWidth={this.props.paneWidth} paneTitle="User Details" lastMenu={detailMenu} dismissible onClose={this.props.onClose}>
        <Row>
          <Col xs={7} >
            <Row>
              <Col xs={12}>

{_.get(user, ['personal', 'lastName'], '')}, {_.get(user, ['personal', 'firstName'], '')} {_.get(user, ['personal', 'middleName'], '')}

              </Col>
            </Row>
            <Row>
              <Col xs={12}>
                <KeyValue label="User ID" value={_.get(user, ['username'], '')} />
              </Col>
            </Row>

            <Row>
              <Col xs={12}>
                <KeyValue label="Status" value={userStatus} />
              </Col>
            </Row>

            <Row>
              <Col xs={12}>
                <KeyValue label="Email" value={_.get(user, ['personal', 'email'], '')} />
              </Col>
            </Row>

            <Row>
              <Col xs={12}>
                <KeyValue label="Phone" value={_.get(user, ['personal', 'phone'], '')} />
              </Col>
            </Row>

            <Row>
              <Col xs={12}>
                <KeyValue label="Mobile phone" value={_.get(user, ['personal', 'mobilePhone'], '')} />
              </Col>
            </Row>

            <Row>
              <Col xs={12}>
                <KeyValue label="Date of birth" value={(_.get(user, ['personal', 'dateOfBirth'], '')) ? new Date(Date.parse(_.get(user, ['personal', 'dateOfBirth'], ''))).toLocaleDateString(this.props.stripes.locale) : ''} />
              </Col>
            </Row>

            <Row>
              <Col xs={12}>
                <KeyValue label="Patron group" value={patronGroup.desc} />
              </Col>
            </Row>
          </Col>
          <Col xs={5} >
            <Row>
              <Col xs={12}>

              </Col>
            </Row>

            <Row>
              <Col xs={12}>
                <KeyValue label="Date enrolled" value={(_.get(user, ['enrollmentDate'],'')) ? new Date(Date.parse(_.get(user, ['enrollmentDate'], ''))).toLocaleDateString(this.props.stripes.locale) : ''} />
              </Col>
            </Row>
            <Row>
              <Col xs={12}>
                <KeyValue label="Expiration date" value={(_.get(user, ['expirationDate'],'')) ? new Date(Date.parse(_.get(user, ['expirationDate'], ''))).toLocaleDateString(this.props.stripes.locale) : ''} />
              </Col>
            </Row>
            <Row>
              <Col xs={12}>
                <KeyValue label="Bar code" value={_.get(user, ['barcode'], '')} />
              </Col>
            </Row>
            <Row>
              <Col xs={12}>
                <KeyValue label="FOLIO record number" value={_.get(user, ['id'], '')} />
              </Col>
            </Row>
            <Row>
              <Col xs={12}>
                <KeyValue label="External System ID" value={_.get(user, ['externalSystemId'], '')} />
              </Col>
            </Row>
          </Col>
        </Row>

        <Row>
          <Col xs={3}>

Fines

          </Col>
          <Col xs={4} sm={3}>
            <TextField
              rounded
              endControl={<Button buttonStyle="fieldControl"><Icon icon="clearX" /></Button>}
              startControl={<Icon icon="search" />}
              placeholder="Search"
              fullWidth
            />
          </Col>
          <Col xs={5} sm={6}>
            <Button align="end" bottomMargin0 >View Full History</Button>
          </Col>
        </Row>
        <MultiColumnList fullWidth contentData={fineHistory} />

        <IfPermission perm="circulation.loans.collection.get">
          <this.connectedUserLoans onClickViewLoansHistory={this.onClickViewLoansHistory} {...this.props} />
        </IfPermission>
        <IfPermission perm="perms.users.get">
          <this.connectedUserPermissions stripes={this.props.stripes} match={this.props.match} {...this.props} />
        </IfPermission>
        <Layer isOpen={this.props.data.editMode ? this.props.data.editMode.mode : false} label="Edit User Dialog">
          <UserForm
            initialValues={_.merge(user, { available_patron_groups: this.props.data.patronGroups })}
            onSubmit={(record) => { this.update(record); }}
            onCancel={this.onClickCloseEditUser}
            okapi={this.props.okapi}
          />
        </Layer>
        <Layer isOpen={this.state.viewLoansHistoryMode} label="Loans History">
          <this.connectedLoansHistory userid={userid} stripes={this.props.stripes} onCancel={this.onClickCloseLoansHistory} />
        </Layer>
      </Pane>
    );
  }
}

export default ViewUser;
<|endoftext|>


<commit_before>import d3 from 'd3';

var pieDiv = d3.select('body').append('div').attr('class', 'toolTip');

const pieWidth = 500;
const pieHeight = 500;
const pieRadius = Math.min(pieWidth, pieHeight) / 2;

function getRandomColor() {
	var letters = '0123456789ABCDEF';
	var color = '#';
	for (var i = 0; i < 6; i++ ) {
		color += letters[Math.floor(Math.random() * 16)];
	}
	return color;
}

const arc = d3.arc()
	.outerRadius(pieRadius - 10)
	.innerRadius(pieRadius - 70);

const pie = d3.pie()
	.sort(null)
	.value(d => d.value);

const svgPie = d3.select('body').append('svg')
	.attr('width', pieWidth)
	.attr('height', pieHeight)
	.append('g')
	.attr('transform', `translate(${pieWidth / 2},${pieHeight / 2})`);

const g = svgPie.selectAll('.arc')
	.data(pie(data))
	.enter().append('g')
	.attr('class', 'arc');

g.append('path')
	.attr('d', arc)
	.style('fill', d => getRandomColor(d.data.label));

g
	.on('mousemove', function(d){
		pieDiv.style('left', d3.event.pageX+10+'px');
		pieDiv.style('top', d3.event.pageY-25+'px');
		pieDiv.style('display', 'inline-block');
		pieDiv.html((d.data.label)+'
'+(d.value)+'Vote(s)');
	});

g
	.on('mouseout', function(d){
		pieDiv.style('display', 'none');
	});
g.append('text')
	.attr('transform', (d) => {
		console.log(d);
		return `translate(${arc.centroid(d)})`;
	})
	.attr('dy', '.35em')
	.text((d) => d.data.label)
	.attr('class', 'value');

var div = d3.select('body').append('div').attr('class', 'toolTip');

var axisMargin = 20,
	margin = 40,
	valueMargin = 4,
	width = parseInt(d3.select('body').style('width'), 10),
	height = parseInt(d3.select('body').style('height'), 10),
	barHeight = (height-axisMargin-margin*2)* 0.4/data.length,
	barPadding = (height-axisMargin-margin*2)*0.4/data.length,
	data, bar, svg, scale, xAxis, labelWidth = 0;
width *= .5;
height *= .8;
console.log(width);
max = d3.max(data, function(d) { return d.value; });

svg = d3.select('body')
	.append('svg')
	.attr('width', width)
	.attr('height', height);

bar = svg.selectAll('g')
	.data(data)
	.enter()
	.append('g');

bar.attr('class', 'bar')
	.attr('cx',0)
	.attr('transform', function(d, i) {
		return 'translate(' + margin + ',' + (i * (barHeight + barPadding) + barPadding) + ')';
	});

bar.append('text')
	.attr('class', 'value2')
	.attr('y', barHeight / 2)
	.attr('dy', '.35em') //vertical align middle
	.text(function(d){
		return d.label;
	}).each(function() {
	labelWidth = Math.ceil(Math.max(labelWidth, this.getBBox().width));
});

scale = d3.scaleLinear()
	.domain([0, max + max *0.20])
	.range([0, width - margin*2 - labelWidth]);

xAxis = d3.axisBottom()
	.scale(scale)
	.tickSize(-height + 2*margin + axisMargin)

bar.append('rect')
	.attr('transform', 'translate('+labelWidth+', 0)')
	.attr('height', barHeight)
	.attr('width', function(d){
		return scale(d.value);
	});

bar.append('text')
	.attr('class', 'value')
	.attr('y', barHeight / 2)
	.attr('dx', -valueMargin + labelWidth) //margin right
	.attr('dy', '.35em') //vertical align middle
	.attr('text-anchor', 'end')
	.text(function(d){
		return (d.value+' Vote(s)');
	})
	.attr('x', function(d){
		var width = this.getBBox().width;
		return Math.max(width + valueMargin, scale(d.value));
	});

bar
	.on('mousemove', function(d){
		div.style('left', d3.event.pageX+10+'px');
		div.style('top', d3.event.pageY-25+'px');
		div.style('display', 'inline-block');
		div.html((d.label)+'
'+(d.value)+'Vote(s)');
	});
bar
	.on('mouseout', function(d){
		div.style('display', 'none');
	});

svg.insert('g',':first-child')
	.attr('class', 'axisHorizontal')
	.attr('transform', 'translate(' + (margin + labelWidth) + ','+ (height - axisMargin - margin)+')')
	.call(xAxis);
<commit_msg>es6 via lebab<commit_after>import d3 from 'd3';

const pieDiv = d3.select('body').append('div').attr('class', 'toolTip');

const pieWidth = 500;
const pieHeight = 500;
const pieRadius = Math.min(pieWidth, pieHeight) / 2;

function getRandomColor() {
	const letters = '0123456789ABCDEF';
	let color = '#';
	for (let i = 0; i < 6; i++ ) {
		color += letters[Math.floor(Math.random() * 16)];
	}
	return color;
}

const arc = d3.arc()
	.outerRadius(pieRadius - 10)
	.innerRadius(pieRadius - 70);

const pie = d3.pie()
	.sort(null)
	.value(d => d.value);

const svgPie = d3.select('body').append('svg')
	.attr('width', pieWidth)
	.attr('height', pieHeight)
	.append('g')
	.attr('transform', `translate(${pieWidth / 2},${pieHeight / 2})`);

const g = svgPie.selectAll('.arc')
	.data(pie(data))
	.enter().append('g')
	.attr('class', 'arc');

g.append('path')
	.attr('d', arc)
	.style('fill', d => getRandomColor(d.data.label));

g
	.on('mousemove', d => {
		pieDiv.style('left', `${d3.event.pageX+10}px`);
		pieDiv.style('top', `${d3.event.pageY-25}px`);
		pieDiv.style('display', 'inline-block');
		pieDiv.html(`${d.data.label}<br>${d.value}Vote(s)`);
	});

g
	.on('mouseout', d => {
		pieDiv.style('display', 'none');
	});
g.append('text')
	.attr('transform', (d) => {
		console.log(d);
		return `translate(${arc.centroid(d)})`;
	})
	.attr('dy', '.35em')
	.text((d) => d.data.label)
	.attr('class', 'value');

const div = d3.select('body').append('div').attr('class', 'toolTip');

const axisMargin = 20;
const margin = 40;
const valueMargin = 4;
let width = parseInt(d3.select('body').style('width'), 10);
let height = parseInt(d3.select('body').style('height'), 10);
const barHeight = (height-axisMargin-margin*2)* 0.4/data.length;
const barPadding = (height-axisMargin-margin*2)*0.4/data.length;
var data;
let bar;
let svg;
let scale;
let xAxis;
let labelWidth = 0;
width *= .5;
height *= .8;
console.log(width);
max = d3.max(data, d => d.value);

svg = d3.select('body')
	.append('svg')
	.attr('width', width)
	.attr('height', height);

bar = svg.selectAll('g')
	.data(data)
	.enter()
	.append('g');

bar.attr('class', 'bar')
	.attr('cx',0)
	.attr('transform', (d, i) => `translate(${margin},${i * (barHeight + barPadding) + barPadding})`);

bar.append('text')
	.attr('class', 'value2')
	.attr('y', barHeight / 2)
	.attr('dy', '.35em') //vertical align middle
	.text(d => d.label).each(function() {
	labelWidth = Math.ceil(Math.max(labelWidth, this.getBBox().width));
});

scale = d3.scaleLinear()
	.domain([0, max + max *0.20])
	.range([0, width - margin*2 - labelWidth]);

xAxis = d3.axisBottom()
	.scale(scale)
	.tickSize(-height + 2*margin + axisMargin)

bar.append('rect')
	.attr('transform', `translate(${labelWidth}, 0)`)
	.attr('height', barHeight)
	.attr('width', d => scale(d.value));

bar.append('text')
	.attr('class', 'value')
	.attr('y', barHeight / 2)
	.attr('dx', -valueMargin + labelWidth) //margin right
	.attr('dy', '.35em') //vertical align middle
	.attr('text-anchor', 'end')
	.text(d => `${d.value} Vote(s)`)
	.attr('x', function(d){
		const width = this.getBBox().width;
		return Math.max(width + valueMargin, scale(d.value));
	});

bar
	.on('mousemove', d => {
		div.style('left', `${d3.event.pageX+10}px`);
		div.style('top', `${d3.event.pageY-25}px`);
		div.style('display', 'inline-block');
		div.html(`${d.label}<br>${d.value}Vote(s)`);
	});
bar
	.on('mouseout', d => {
		div.style('display', 'none');
	});

svg.insert('g',':first-child')
	.attr('class', 'axisHorizontal')
	.attr('transform', `translate(${margin + labelWidth},${height - axisMargin - margin})`)
	.call(xAxis);

<|endoftext|>


<commit_before>var htmlparser = require('htmlparser2');
var https = require('https');
var http = require('http');
var fs = require('fs');
var crypto = require('crypto');
var mongo = require('mongodb');
var cron = require('node-schedule');

var base = 'https://web.archive.org';
var urls = {'https://web.archive.org/web/2014*/http://jw.org/en':true,'https://web.archive.org/web/2013*/http://jw.org/en':true,'https://web.archive.org/web/2012*/http://jw.org/en':true};
var cache = {};
function it(base,urls,regex,attr,end){
	console.log(urls);
	var reg = new RegExp(regex);
	var cnt = 0;
	var  max = urls.length;
	if(max === udefined){
		max = 0;
		for( url in urls)max++;
	}
	var arr = {};
	function _do(url){
		var parser = new htmlparser.Parser({
			onattribute:function(name,val){
				if(name == attr && reg.test(val)){
					if(val.indexOf(base) == 0)
						arr[val] = url;
					else
						arr[base+val] = url;
				}
			}
		});
		if(!cache[url]){
			console.log('cache miss '+url);
			var req = https.get(url,function(res){
				res.on('data',function(data){
					parser.write(data)
				}).on('end',function(){
					console.log('parsed '+this.req.path+' for '+url);
					parser.end();
					console.log(arr);
					cache[this.req.path] = true;
					cnt++;
					if(cnt == max)
						end(arr)
					else console.log(cnt +' '+max);
				}).on('error',function(err){console.log(err);cnt++;});
			}).on('error',function(err){console.log(err);cnt++});
		}else {console.log('cached '+url);cnt++}
	}
	for( url in urls ){
		_do(url);
	}
}

it(base,urls,'.*http://www.jw.org/','href',function(arr){
	it('http://assets.jw.org/',arr,'.*assets/.*/[0-9]+.*(pnr|cnt).*lg.jpg','data-img-size-lg',function(arr){
		mongo.connect('mongodb://localhost:27017/jwscrapper',function(err,db){
			console.log('saving');
			console.log(arr);
			if(err)throw err;
			console.log('connected');
			var docs = [];
			function _from(val){
				var arr = [];
				var value = val.match(/web.([0-9]+).http/)[1];
				for(var idx in [4,2,2,2]){
					arr.push()
				}
				return
			}
			for(var url in arr) docs.push({'_id':url,'from':_from(arr[url])});
			db.collection('imgs').insert(docs,{w:1},function(err,result){
				console.log(result);
			});
			db.close();
		});
	});
});

function foreach(arr,proc,end){
	this._arr = [];
	for(var idx in arr){
		if(idx === arr.length - 1)
		  proc.call(this,idx,arr[idx],end);
		else proc.call(this,idx,arr[idx]);
	}
}

function invoke(idx,item,res,end){
	this._token = 'init';
	this._readtext = false;
	this._item = {};

	var parser = new htmlparser.Parser({
		onopentag:function(name,attribs){
			if(this._token === 'init' && name === 'li' && attribs.class && attribs.class.match(/\s*sliderItem\s*/)){
				this._token = name;
			}else if(this._token === 'li'){
				if(name === 'div' && attribs.class && attribs.class.match(/\s*jsImgDescr\s*/){
					this._token = 'facts';
				}
			}else if(this._token === 'facts'){
				if(name === 'h2' || name === 'h3'){
					this._token = name;
				}else if(name === 'p'){
					if(attribs.id === 'p2')this._token = 'population'
					else if(attribs.id === 'p3')this._token = 'ministers'
					else if(attribs.id === 'p4')this._token = 'congregations'
					else if(attribs.id === 'p5')this._token = 'rate'
					this._readtext = true;
					this._item[this._token] = [];
				}
			}
			if(name === 'span' && attribs.class && attribs.class.match(/\s*jsRespImg\s*/)){
				var o = {};
				for(var att in attribs)
					if(att.match(/data-image-size-\w{2}/)){
						o[att] = attribs[att];
					}
				this._item.images = o;
			}
		},
		ontext:function(text){
			if(this._readtext)
				this._item[this._token].push(text);
			}
		},
		onclosetag:function(name){
			if(this._token === 'end'){
				this._arr.push(this._item);
				this._token = 'init';
			}else if(name === 'h2' || name === 'h3'){
				this._token = 'facts';
			}else if(this._token === 'population' ||
				this._token === 'ministers' ||
				this._token === 'congregations' ||
				this._token === 'rate'){
					this._token = 'facts';
			}
		}
	});
	if(!cache[url]){
		console.log('cache miss '+url);
		var req = https.get(url,function(res){
			res.on('data',function(data){
				parser.write(data)
			}).on('end',function(){
				console.log('parsed '+this.req.path+' for '+url);
				parser.end();
				console.log(this.arr);
				cache[this.req.path] = true;
				if(end)
					end(this.arr)
			}).on('error',function(err){console.log(err);cnt++;});
		}).on('error',function(err){console.log(err);cnt++});
	}else {console.log('cached '+url);cnt++}
}
<commit_msg>Almost done...<commit_after>var htmlparser = require('htmlparser2');
//var https = require('https');
//var http = require('http');
var fs = require('fs');
var crypto = require('crypto');
var mongo = require('mongodb');
var cron = require('node-schedule');

var base = 'https://web.archive.org';
var urls = ['http://www.jw.org/en/']//['https://web.archive.org/web/2014*/http://jw.org/en',
						//'https://web.archive.org/web/2013*/http://jw.org/en',
						//'https://web.archive.org/web/2012*/http://jw.org/en'];
var cache = {};

function foreach(arr,proc,end){
	(function(){
	this._arr = [];
	for(var idx in arr){
		console.log('%d %d',idx,arr.length)
		if(idx == arr.length - 1)
		  proc.call(this,idx,arr[idx],end);
		else proc.call(this,idx,arr[idx]);
	}})();
}

function invoke(idx,url,end){
	this._token = 'init';
	this._readtext = false;
	this._item = {};
	var self = this;
	var parser = new htmlparser.Parser({
		onopentag:function(name,attribs){
			function dbg(){
				console.log('onopentag %s %s %s',name,self._token,self._readtext);
				console.log(self._item);
				console.log(attribs);
			}
			if(name === 'li' && attribs.class && attribs.class.match(/\s*sliderItem\s*/)){
				dbg();
				if(self._item.images !== undefined){
					self._arr.push(self._item);
					self._item = {};
				}
				self._token = name;
			}else if(self._token === 'li'){
				if(name === 'div' && attribs.class && attribs.class.match(/\s*jsImgDescr\s*/)){
					dbg();
					self._token = 'facts';
				}
			}else if(self._token === 'facts'){
			 if(name === 'p' || name === 'h2' || name === 'h3'){
					dbg();
					if(attribs.id === 'p2')self._token = 'population'
					else if(attribs.id === 'p3')self._token = 'ministers'
					else if(attribs.id === 'p4')self._token = 'congregations'
					else if(attribs.id === 'p5')self._token = 'rate'
					else self._token = name;
					self._readtext = true;
					self._item[self._token] = [];
				}
			}
			if(name === 'span' && attribs.class && attribs.class.match(/\s*jsRespImg\s*/)){
				dbg();
				var o = {};
				var add = false;
				for(var att in attribs)
					if(att.match(/data-img-size-\w{2}/)){
						o[att] = attribs[att];
						add = true;
					}
				if(add)
					self._item.images = o;
				console.log(self._item);
			}
		},
		ontext:function(text){
			if(self._readtext){
				console.log('ontext %s %s %s',text,self._token,self._readtext);
				self._item[self._token].push(text);
				console.log(self._item);
			}

		},
		onclosetag:function(name){
			function dbg(){
				console.log('onclosetag %s %s %s',name,self._token,self._readtext);
				console.log(self._item);
				console.log(self._arr);
			}
			if(self._readtext){
				dbg();
				self._token = 'facts';
				self._readtext = false;

			}
		}
	});
	if(!cache[url]){
		console.log('cache miss '+url);
		var proto = url.match(/https:.*/)?require('https'):require('http');
		var req = proto.get(url,function(res){
			res.on('data',function(data){
				parser.write(data)
			}).on('end',function(){
				console.log('parsed '+this.req.path+' for '+url);
				parser.end();
				cache[this.req.path] = true;
				console.log(end);
				if(end)
					end(self._arr)
			}).on('error',function(err){console.log(err);cnt++;});
		}).on('error',function(err){console.log(err);cnt++});
	}else {console.log('cached '+url);cnt++}
}
foreach(urls,invoke,function(arr){
	console.log(arr);
})
<|endoftext|>


<commit_before>"use strict"

let fs = require('fs-extra')
let utils = require('../adr_util_sync.js').createUtilContext()

let nodeJSCode = (id,title) => `{id : ${id}, label : "${title}", shape : 'box'}`

let diagramHTMLFor = (title,nodes,edges) => `
<!doctype html>

  <title>${title}</title>

  <link href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis-network.min.css" rel="stylesheet" type="text/css" />

  Architecture Decision Records and their references

`

function outputDiagram(filename,html)
{
  console.info(`Outputting diagram to ${filename} ...`)
  fs.outputFile(filename,html)
    .then(() => { console.info("Done.")})
    .catch((err) => { console.error(err)})
}

let edgeJSCode = (source,target,label) => `{from : ${source}, to: ${target}, label: "${label}", arrows : { to : {enabled : true}}}`

let diagramCmd = (outputFile) => {
    console.info("Extracting metadata...")
    let allADRsMetadata = utils.adrFiles.map(utils.metadataFor)
    console.info("Generating HTML...")
    let diagramNodesJSCode = allADRsMetadata.map(adrMD => nodeJSCode(adrMD.id,adrMD.title)).join(",")
    let allEdges = []
    allADRsMetadata.forEach(adrMD => {
        let linksFromThisADR = adrMD.links.map( linkMD => edgeJSCode(adrMD.id, linkMD.target, linkMD.text)).join(",")
        allEdges.push(linksFromThisADR)
    })
    let diagramEdgesJSCode = allEdges.filter(edgesJS => edgesJS != "").join(",")
    let html = diagramHTMLFor("ADRs",diagramNodesJSCode,diagramEdgesJSCode)
    outputDiagram(outputFile || "diagram.html",html)
}

module.exports = diagramCmd<commit_msg>switching to hierarchical layout in result report<commit_after>"use strict"

let fs = require('fs-extra')
let utils = require('../adr_util_sync.js').createUtilContext()

let nodeJSCode = (id,title) => `{id : ${id}, label : "${id}: ${title}", shape : 'box'}`

let diagramHTMLFor = (title,nodes,edges) => `
<!doctype html>

  <title>${title}</title>

  <link href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis-network.min.css" rel="stylesheet" type="text/css" />

  Architecture Decision Records and their references

`

function outputDiagram(filename,html)
{
  console.info(`Outputting diagram to ${filename} ...`)
  fs.outputFile(filename,html)
    .then(() => { console.info("Done.")})
    .catch((err) => { console.error(err)})
}

let edgeJSCode = (source,target,label) => `{from : ${source}, to: ${target}, label: "${label}", arrows : { to : {enabled : true}}}`

let diagramCmd = (outputFile) => {
    console.info("Extracting metadata...")
    let allADRsMetadata = utils.adrFiles.map(utils.metadataFor)
    console.info("Generating HTML...")
    let diagramNodesJSCode = allADRsMetadata.map(adrMD => nodeJSCode(adrMD.id,adrMD.title)).join(",")
    let allEdges = []
    allADRsMetadata.forEach(adrMD => {
        let linksFromThisADR = adrMD.links.map( linkMD => edgeJSCode(adrMD.id, linkMD.target, linkMD.text)).join(",")
        allEdges.push(linksFromThisADR)
    })
    let diagramEdgesJSCode = allEdges.filter(edgesJS => edgesJS != "").join(",")
    let html = diagramHTMLFor("ADRs",diagramNodesJSCode,diagramEdgesJSCode)
    outputDiagram(outputFile || "diagram.html",html)
}

module.exports = diagramCmd<|endoftext|>


<commit_before>/**
 * The router module.
 *
 * Router handles app routing and URL parameters and updates Presenter.
 *
 * @return singleton instance of Router class (extends Backbone.Router).
 */
define([
  'underscore',
  'backbone',
  'amplify',
  'map/utils',
  'map/services/PlaceService'
], function(_, Backbone, amplify, utils, PlaceService) {

  'use strict';

  var Router = Backbone.Router.extend({

    // temporary, we will do it with env variables
    _cacheVersion: 14,

    routes: {
      'map(/:zoom)(/:lat)(/:lng)(/:iso)(/:maptype)(/:baselayers)(/:sublayers)(/)': 'map',
      'embed/map(/:zoom)(/:lat)(/:lng)(/:iso)(/:maptype)(/:baselayers)(/:sublayers)(/)': 'embed'
    },

    /**
     * Boot file:
     *
     * @param  {[type]} boot [description]
     */
    initialize: function(mainView) {
      this.bind('all', this._checkForCacheBust());
      this.name = null;
      this.mainView = mainView;
      this.placeService = new PlaceService(this);
    },

    map: function() {
      this.name = 'map';
      this.mainView.setMapMode();
      this.initMap.apply(this, arguments);
    },

    embed: function() {
      this.name = 'embed/map';
      this.initMap.apply(this, arguments);
    },

    initMap: function(zoom, lat, lng, iso, maptype, baselayers, sublayers, subscribe) {
      var params = _.extend({
        zoom: zoom,
        lat: lat,
        lng: lng,
        iso: iso,
        maptype: maptype,
        baselayers: baselayers,
        sublayers: sublayers,
        subscribe_alerts: subscribe
      }, _.parseUrl());
      this.placeService.initPlace(this.name, params);
    },

    /**
     * If the URL contains the cache parameter (e.g., cache=bust), clear all
     * cached values in the browser (e.g., from memory, local storage,
     * session).
     */
    _checkForCacheBust: function() {
      var params = _.parseUrl();
      var localCacheVersion = _.toNumber(
        localStorage.getItem('CACHE_VERSION'));

      if (_.has(params, 'cache') || localCacheVersion !== this._cacheVersion) {
        console.log('...');
        _.each(amplify.store(), function(value, key) {
          amplify.store(key, null);
        });

        localStorage.setItem('CACHE_VERSION', this._cacheVersion);
      }
    },

    navigateTo: function(route, options) {
      this.navigate(route, options);
    }

  });

  return Router;

});
<commit_msg>cache version ++<commit_after>/**
 * The router module.
 *
 * Router handles app routing and URL parameters and updates Presenter.
 *
 * @return singleton instance of Router class (extends Backbone.Router).
 */
define([
  'underscore',
  'backbone',
  'amplify',
  'map/utils',
  'map/services/PlaceService'
], function(_, Backbone, amplify, utils, PlaceService) {

  'use strict';

  var Router = Backbone.Router.extend({

    // temporary, we will do it with env variables
    _cacheVersion: 15,

    routes: {
      'map(/:zoom)(/:lat)(/:lng)(/:iso)(/:maptype)(/:baselayers)(/:sublayers)(/)': 'map',
      'embed/map(/:zoom)(/:lat)(/:lng)(/:iso)(/:maptype)(/:baselayers)(/:sublayers)(/)': 'embed'
    },

    /**
     * Boot file:
     *
     * @param  {[type]} boot [description]
     */
    initialize: function(mainView) {
      this.bind('all', this._checkForCacheBust());
      this.name = null;
      this.mainView = mainView;
      this.placeService = new PlaceService(this);
    },

    map: function() {
      this.name = 'map';
      this.mainView.setMapMode();
      this.initMap.apply(this, arguments);
    },

    embed: function() {
      this.name = 'embed/map';
      this.initMap.apply(this, arguments);
    },

    initMap: function(zoom, lat, lng, iso, maptype, baselayers, sublayers, subscribe) {
      var params = _.extend({
        zoom: zoom,
        lat: lat,
        lng: lng,
        iso: iso,
        maptype: maptype,
        baselayers: baselayers,
        sublayers: sublayers,
        subscribe_alerts: subscribe
      }, _.parseUrl());
      this.placeService.initPlace(this.name, params);
    },

    /**
     * If the URL contains the cache parameter (e.g., cache=bust), clear all
     * cached values in the browser (e.g., from memory, local storage,
     * session).
     */
    _checkForCacheBust: function() {
      var params = _.parseUrl();
      var localCacheVersion = _.toNumber(
        localStorage.getItem('CACHE_VERSION'));

      if (_.has(params, 'cache') || localCacheVersion !== this._cacheVersion) {
        console.log('...');
        _.each(amplify.store(), function(value, key) {
          amplify.store(key, null);
        });

        localStorage.setItem('CACHE_VERSION', this._cacheVersion);
      }
    },

    navigateTo: function(route, options) {
      this.navigate(route, options);
    }

  });

  return Router;

});
<|endoftext|>


<commit_before>var mongoose = require("mongoose");
var Anime   = require('../models/anime');

// Database
var config = require('../config/config');
mongoose.connect(config.database);

Anime.create({"_id": "20", title: "test"})

console.log("done")<commit_msg>models connected with references<commit_after>var mongoose = require("mongoose");
var Anime   = require('../models/anime');

// Database
var config = require('../config/config');
mongoose.connect(config.database);

Anime.create({"_id": "20", title: "test", comments: []})

console.log("done")<|endoftext|>