<commit_before>oT.backup = {};

oT.backup.openPanel = function(){
    oT.backup.populatePanel();
    $('.backup-window').height( $('.textbox-container').height() * (3/5) );
    $('.backup-panel').fadeIn('fast');
}

oT.backup.closePanel = function(){
    $('.backup-panel').fadeOut('fast',function(){
        $('.backup-window').empty();

    });
}

oT.backup.generateBlock = function(ref){
    // create icon and 'restore' button
    var text = localStorage.getItem(ref);
    var timestamp = ref.replace('oTranscribe-backup-','');
    var date = oT.backup.formatDate(timestamp);

    var block = document.createElement('div');
    var doc = document.createElement('div');
    var restoreButton = document.createElement('div');

    block.className = 'backup-block';
    doc.className = 'backup-doc';
    restoreButton.className = 'backup-restore-button';

    doc.innerHTML = text;
    restoreButton.innerHTML = date+' - restore';
    block.appendChild(doc);
    block.appendChild(restoreButton);

    return block;
}

oT.backup.formatDate = function(timestamp){
    var d = new Date( parseFloat(timestamp) );
    var day =  d.getDate() + '/' + (d.getMonth()+1);
    var now = new Date();
    today = now.getDate() + '/' + (now.getMonth()+1);
    yesterday = (now.getDate()-1) + '/' + (now.getMonth()+1);
    if (day === today) {
        day = 'Today';
    } else if (day === yesterday) {
        day = 'Yesterday'
    }
    var time = d.getHours() + ':';
    if (d.getMinutes() < 10) {
        time += '0';
    }
    time += d.getMinutes();

    formattedDate = day + ' ' + time;
    return formattedDate;
}

oT.backup.populatePanel = function(){
    oT.backup.addDocsToPanel(0,8);
    if (oT.backup.list().length === 0) {
        $('.backup-window').append( '
No backups found.
' );
    }
}

oT.backup.addDocsToPanel = function(start,end){
    $('.more-backups').remove();
    var allDocs = oT.backup.list();
    docs = allDocs.slice(start,end);
    for (var i = 0; i < docs.length; i++) {
        $('.backup-window').append( oT.backup.generateBlock(docs[i]) );
    }
    if (allDocs[end]) {
        $('.backup-window').append( '
Load older backups
' );
    }
}

oT.backup.save = function(){
    // save current text to timestamped localStorage item
    var text = document.getElementById("textbox");
    var timestamp = new Date().getTime();
    localStorage.setItem('oTranscribe-backup-'+timestamp, text.innerHTML);
    // and bleep icon
    $('.sbutton.backup').addClass('flash');
    setTimeout(function(){
        $('.sbutton.backup').removeClass('flash');
    },1000);
    // and add to tray
    var newBlock = oT.backup.generateBlock('oTranscribe-backup-'+timestamp);
    newBlock.className += ' new-block';
    $('.backup-window').prepend( newBlock );
    $( newBlock ).animate({
        'opacity': 1,
        'width': '25%'
    },'slow',function(){
        $( newBlock ).find('.backup-restore-button').fadeIn();
    });

}

oT.backup.init = function(){
    setInterval(function(){
        oT.backup.save();
        oT.backup.cleanup();
    },300000 /* 5 minutes */);
}

oT.backup.list = function(){
    var result = [];
    for (var i = 0; i < localStorage.length; i++) {
        if (localStorage.key(i).indexOf('oTranscribe-backup') > -1) {
            result.push(localStorage.key(i));
        }
    }
    return result.sort().reverse();
}

oT.backup.restore = function(timestamp){
    oT.backup.save();
    var textbox = document.getElementById("textbox");
    var newText = localStorage.getItem('oTranscribe-backup-'+timestamp);
    document.getElementById("textbox").innerHTML = newText;
    oT.backup.closePanel();
}

oT.backup.cleanup = function(){
    var backups = oT.backup.list();
    for (var i = 0; i < backups.length; i++) {
        var bu = backups[i];
        var ts = bu.replace('oTranscribe-backup-','');
        var date = new Date( parseFloat( ts ) );
        var diff = Date.now() - date;
        // 1 day = 86400000 miliseconds
        if (diff > (86400000*7) ) {
            localStorage.removeItem( bu );
        }
    }
}

// original autosave function
function saveText(){
    var field = document.getElementById("textbox");
    // load existing autosave (if present)
    if ( localStorage.getItem("autosave")) {
       field.innerHTML = localStorage.getItem("autosave");
    }
    // autosave every second - but wait five seconds before kicking in
    setTimeout(function(){
        setInterval(function(){
           localStorage.setItem("autosave", field.innerHTML);
        }, 1000);
    }, 5000);
}
<commit_msg>Mid-debugging<commit_after>oT.backup = {};

oT.backup.openPanel = function(){
    oT.backup.populatePanel();
    $('.backup-window').height( $('.textbox-container').height() * (3/5) );
    $('.backup-panel').fadeIn('fast');
}

oT.backup.closePanel = function(){
    $('.backup-panel').fadeOut('fast',function(){
        $('.backup-window').empty();

    });
}

oT.backup.generateBlock = function(ref){
    // create icon and 'restore' button
    var text = localStorage.getItem(ref);
    var timestamp = ref.replace('oTranscribe-backup-','');
    var date = oT.backup.formatDate(timestamp);

    var block = document.createElement('div');
    var doc = document.createElement('div');
    var restoreButton = document.createElement('div');

    block.className = 'backup-block';
    doc.className = 'backup-doc';
    restoreButton.className = 'backup-restore-button';

    doc.innerHTML = text;
    restoreButton.innerHTML = date+' - restore';
    block.appendChild(doc);
    block.appendChild(restoreButton);

    return block;
}

oT.backup.formatDate = function(timestamp){
    var d = new Date( parseFloat(timestamp) );
    var day =  d.getDate() + '/' + (d.getMonth()+1);
    var now = new Date();
    today = now.getDate() + '/' + (now.getMonth()+1);
    yesterday = (now.getDate()-1) + '/' + (now.getMonth()+1);
    if (day === today) {
        day = 'Today';
    } else if (day === yesterday) {
        day = 'Yesterday'
    }
    var time = d.getHours() + ':';
    if (d.getMinutes() < 10) {
        time += '0';
    }
    time += d.getMinutes();

    formattedDate = day + ' ' + time;
    return formattedDate;
}

oT.backup.populatePanel = function(){
    oT.backup.addDocsToPanel(0,8);
    if (oT.backup.list().length === 0) {
        $('.backup-window').append( '
No backups found.
' );
    }
}

oT.backup.addDocsToPanel = function(start,end){
    $('.more-backups').remove();
    var allDocs = oT.backup.list();
    docs = allDocs.slice(start,end);
    for (var i = 0; i < docs.length; i++) {
        $('.backup-window').append( oT.backup.generateBlock(docs[i]) );
    }
    if (allDocs[end]) {
        $('.backup-window').append( '
Load older backups
' );
    }
}

oT.backup.save = function(){
    // save current text to timestamped localStorage item
    var text = document.getElementById("textbox");
    var timestamp = new Date().getTime();
    oT.backup.saveToLocalStorage('oTranscribe-backup-'+timestamp, text.innerHTML);
    // and bleep icon
    $('.sbutton.backup').addClass('flash');
    setTimeout(function(){
        $('.sbutton.backup').removeClass('flash');
    },1000);
    // and add to tray
    var newBlock = oT.backup.generateBlock('oTranscribe-backup-'+timestamp);
    newBlock.className += ' new-block';
    $('.backup-window').prepend( newBlock );
    $( newBlock ).animate({
        'opacity': 1,
        'width': '25%'
    },'slow',function(){
        $( newBlock ).find('.backup-restore-button').fadeIn();
    });

}

oT.backup.saveToLocalStorage = function(name){
    console.log(name);
    try {
       localStorage.setItem( name );
    } catch (e) {
        console.log('error');
       if(e.name === "NS_ERROR_DOM_QUOTA_REACHED") {
           oT.backup.removeOldest();
           // oT.backup.save();
       }
    }

}

oT.backup.init = function(){
    setInterval(function(){
        oT.backup.save();
        oT.backup.cleanup();
    },300000 /* 5 minutes */);
}

oT.backup.list = function(){
    var result = [];
    for (var i = 0; i < localStorage.length; i++) {
        if (localStorage.key(i).indexOf('oTranscribe-backup') > -1) {
            result.push(localStorage.key(i));
        }
    }
    return result.sort().reverse();
}

oT.backup.restore = function(timestamp){
    oT.backup.save();
    var textbox = document.getElementById("textbox");
    var newText = localStorage.getItem('oTranscribe-backup-'+timestamp);
    document.getElementById("textbox").innerHTML = newText;
    oT.backup.closePanel();
}

oT.backup.cleanup = function(){
    var backups = oT.backup.list();
    for (var i = 0; i < backups.length; i++) {
        var bu = backups[i];
        var ts = bu.replace('oTranscribe-backup-','');
        var date = new Date( parseFloat( ts ) );
        var diff = Date.now() - date;
        // 1 day = 86400000 miliseconds
        if (diff > (86400000*7) ) {
            localStorage.removeItem( bu );
        }
    }
}

oT.backup.removeOldest = function(){
	localStorage.clear();

    var list = oT.backup.list();
    // var toDelete = list.slice(Math.max(list.length - 5, 1));
    var toDelete = list;
    console.log('todelete: ',toDelete);
    for (var i = 0; i < toDelete.length; i++) {
        console.log('deleting '+toDelete[i])
        localStorage.removeItem( toDelete[i] );
    }
}

// original autosave function
function saveText(){
    var field = document.getElementById("textbox");
    // load existing autosave (if present)
    if ( localStorage.getItem("autosave")) {
       field.innerHTML = localStorage.getItem("autosave");
    }
    // autosave every second - but wait five seconds before kicking in
    setTimeout(function(){
        setInterval(function(){
           oT.backup.saveToLocalStorage("autosave", field.innerHTML);
        }, 1000);
    }, 5000);
}
<|endoftext|>


<commit_before>var dust = require("dustjs-linkedin");
var fs = require('fs');

function render(_templateKey, _source, _model, _res) {
	var tmeplate = new String(_source);
	//TODO 상대경로는 어떻게 찾아낼 것인가?
	if(_source.indexOf('.') === 0 || _source.indexOf('/') === 0) {
		tmeplate = fs.readFileSync(_source).toString();
	}
	var compiledSource = dust.compile(tmeplate, _templateKey);

	dust.loadSource(compiledSource);

	var json = "";
	if(_model instanceof String) {
		json = JSON.parse(_model);
		console.log("JSON model parse from " + _model + " to " + json);
	} else {
		json = _model;
	}
	dust.render(_templateKey, json,
		function(_err, _out){
			if(_out) {
				_res.write(_out);
				console.log("3. Rendering success: " + _out);
			}
			if(_err) {
				console.log("3. Rendering error: " + _err);
			}
		}
	);
}

exports.render = render;<commit_msg>dustview 내부 코드 리팩터링<commit_after>var dust = require("dustjs-linkedin");
var fs = require('fs');

function render(_templateKey, _source, _model, _res) {

	var compiledSource = dcompile(_templateKey, _source);

	dloadSource(compiledSource);

	drender(_templateKey, _model, _res);
}

function dcompile(_templateKey, _source) {
	var tmeplate = new String(_source);
	//TODO 상대경로는 어떻게 찾아낼 것인가?
	if(_source.indexOf('.') === 0 || _source.indexOf('/') === 0) {
		tmeplate = fs.readFileSync(_source).toString();
	}
	return dust.compile(tmeplate, _templateKey);
}

function dloadSource(_compiledSource) {
	dust.loadSource(_compiledSource);
}

function drender(_templateKey, _model, _res) {
	var json = "";
	if(_model instanceof String) {
		json = JSON.parse(_model);
		console.log("JSON model parse from " + _model + " to " + json);
	} else {
		json = _model;
	}
	dust.render(_templateKey, json,
		function(_err, _out){
			if(_out) {
				_res.write(_out);
				console.log("3. Rendering success: " + _out);
			}
			if(_err) {
				console.log("3. Rendering error: " + _err);
			}
		}
	);
}

exports.render = render;
exports.dcompile = dcompile;
exports.dloadSource = dloadSource;
exports.drender = drender;<|endoftext|>


<commit_before>/**
 * Created by kimxogus on 2016. 12. 15..
 */
import { isNil, defaultsDeep } from "lodash";
import { Platform } from "react-native";

import Native from "./native";

let latestVersion;
// Used by iOS Only
let appName;
let appID;

export function setAppName(_appName) {
  appName = _appName;
}
export function setAppID(_appID) {
  appID = _appID;
}

export const defaultOption = {
  forceUpdate: false,
  url: null,
  fetchOptions: {
    timeout: 5000
  }
};

export function getLatestVersion(option) {
  option = defaultsDeep(option, defaultOption);

  if (isNil(option.url)) {
    option.url = getStoreUrl(); // To prevent getStore to be executed when it's not needed.
  }

  if (!option.forceUpdate && !isNil(latestVersion)) {
    return Promise.resolve(latestVersion);
  } else {
    return getLatestVersionFromUrl(option.url, option.fetchOptions);
  }
}

function getStoreUrl() {
  if (Platform.OS === "ios" && (!appName || !appID)) {
    throw new Error("'appName' or 'appID' is undefined.\nSet those values correctly using 'setAppName()' and 'setAppID()'");
  }
  return Platform.select({
    android: "https://play.google.com/store/apps/details?id=" + Native.getPackageName(),
    ios: "https://itunes.apple.com/" + Native.getCountry() + "/app/" + appName + "/id" + appID
  });
}

const MARKETVERSION_STARTTOKEN = "softwareVersion\">";
const MARKETVERSION_STARTTOKEN_LENGTH = MARKETVERSION_STARTTOKEN.length;
const MARKETVERSION_ENDTOKEN = "<";
function getLatestVersionFromUrl(url, fetchOptions) {
  return fetch(url, fetchOptions)
    .then(res => {
      return res.text();
    })
    .then((text) => {
      const indexStart = text.indexOf(MARKETVERSION_STARTTOKEN);
      if (indexStart === -1) {
        latestVersion = text.trim();
        return Promise.resolve(latestVersion);
      }

      text = text.substr(indexStart + MARKETVERSION_STARTTOKEN_LENGTH);

      const indexEnd = text.indexOf(MARKETVERSION_ENDTOKEN);
      if (indexEnd === -1) {
        return Promise.reject("Parse error.");
      }

      text = text.substr(0, indexEnd);

      latestVersion = text.trim();
      return Promise.resolve(latestVersion);
    });
}<commit_msg>use array funciton<commit_after>/**
 * Created by kimxogus on 2016. 12. 15..
 */
import { isNil, defaultsDeep } from "lodash";
import { Platform } from "react-native";

import Native from "./native";

let latestVersion;
// Used by iOS Only
let appName;
let appID;

export function setAppName(_appName) {
  appName = _appName;
}
export function setAppID(_appID) {
  appID = _appID;
}

export const defaultOption = {
  forceUpdate: false,
  url: null,
  fetchOptions: {
    timeout: 5000
  }
};

export function getLatestVersion(option) {
  option = defaultsDeep(option, defaultOption);

  if (isNil(option.url)) {
    option.url = getStoreUrl(); // To prevent getStore to be executed when it's not needed.
  }

  if (!option.forceUpdate && !isNil(latestVersion)) {
    return Promise.resolve(latestVersion);
  } else {
    return getLatestVersionFromUrl(option.url, option.fetchOptions);
  }
}

function getStoreUrl() {
  if (Platform.OS === "ios" && (!appName || !appID)) {
    throw new Error("'appName' or 'appID' is undefined.\nSet those values correctly using 'setAppName()' and 'setAppID()'");
  }
  return Platform.select({
    android: "https://play.google.com/store/apps/details?id=" + Native.getPackageName(),
    ios: "https://itunes.apple.com/" + Native.getCountry() + "/app/" + appName + "/id" + appID
  });
}

const MARKETVERSION_STARTTOKEN = "softwareVersion\">";
const MARKETVERSION_STARTTOKEN_LENGTH = MARKETVERSION_STARTTOKEN.length;
const MARKETVERSION_ENDTOKEN = "<";
function getLatestVersionFromUrl(url, fetchOptions) {
  return fetch(url, fetchOptions)
    .then(res => res.text())
    .then(text => {
      const indexStart = text.indexOf(MARKETVERSION_STARTTOKEN);
      if (indexStart === -1) {
        latestVersion = text.trim();
        return Promise.resolve(latestVersion);
      }

      text = text.substr(indexStart + MARKETVERSION_STARTTOKEN_LENGTH);

      const indexEnd = text.indexOf(MARKETVERSION_ENDTOKEN);
      if (indexEnd === -1) {
        return Promise.reject("Parse error.");
      }

      text = text.substr(0, indexEnd);

      latestVersion = text.trim();
      return Promise.resolve(latestVersion);
    });
}<|endoftext|>


<commit_before>var mat4Multiply = require('gl-mat4/multiply')
var mat4Scale = require('gl-mat4/scale')
var mat4Transpose = require('gl-mat4/transpose')

module.exports = ParseLibraryAnimations

// TODO: parse interpolation
// TODO: Don't hard code attribute location
// TODO: Don't assume that joint animations are in order
// TODO: Inefficient. use depth first traversal
function ParseLibraryAnimations (library_animations, jointBindPoses, visualSceneData) {
  var animations = library_animations[0].animation
  var allKeyframes = {}
  var keyframeJointMatrices = {}
  var jointRelationships = visualSceneData.jointRelationships
  var armatureScale = visualSceneData.armatureScale

  // First pass.. get all the joint matrices
  animations.forEach(function (anim, animationIndex) {
    if (anim.$.id.indexOf('pose_matrix') !== -1) {
      // TODO: Is this the best way to get an animations joint target?
      var animatedJointName = anim.channel[0].$.target.split('/')[0]

      var currentKeyframes = anim.source[0].float_array[0]._.split(' ').map(Number)

      var currentJointPoseMatrices = anim.source[1].float_array[0]._.split(' ').map(Number)

      currentKeyframes.forEach(function (_, keyframeIndex) {
        keyframeJointMatrices[currentKeyframes[keyframeIndex]] = keyframeJointMatrices[currentKeyframes[keyframeIndex]] || {}
        var currentJointMatrix = currentJointPoseMatrices.slice(16 * keyframeIndex, 16 * keyframeIndex + 16)
        if (!jointRelationships[animatedJointName].parent) {
          // apply library visual scene transformations to top level parent joint(s)
          mat4Scale(currentJointMatrix, currentJointMatrix, armatureScale)
        }

        keyframeJointMatrices[currentKeyframes[keyframeIndex]][animatedJointName] = currentJointMatrix
      })
    }
  })
  // Second pass.. Calculate world matrices
  animations.forEach(function (anim, animationIndex) {
    if (anim.$.id.indexOf('pose_matrix') !== -1) {
      var animatedJointName = anim.channel[0].$.target.split('/')[0]
      var currentKeyframes = anim.source[0].float_array[0]._.split(' ').map(Number)
      currentKeyframes.forEach(function (_, keyframeIndex) {
        var currentKeyframe = currentKeyframes[keyframeIndex]
        allKeyframes[currentKeyframes[keyframeIndex]] = allKeyframes[currentKeyframe] || []

        // Multiply by parent world matrix
        var jointWorldMatrix = getParentWorldMatrix(animatedJointName, currentKeyframe, jointRelationships, keyframeJointMatrices)

        // Multiply our joint's inverse bind matrix
        mat4Multiply(jointWorldMatrix, jointBindPoses[animatedJointName], jointWorldMatrix)

        // Turn our row major matrix into a column major matrix. OpenGL uses column major
        mat4Transpose(jointWorldMatrix, jointWorldMatrix)

        // Trim to 6 significant figures (Maybe even 6 is more than needed?)
        jointWorldMatrix = jointWorldMatrix.map(function (val) {
          return parseFloat(val.toFixed(6))
        })

        allKeyframes[currentKeyframe].push(jointWorldMatrix)
      })
    }
  })

  return allKeyframes
}

// TODO: Refactor. Depth first traversal might make all of this less hacky
function getParentWorldMatrix (jointName, keyframe, jointRelationships, keyframeJointMatrices, accumulator) {
  // child -> parent -> parent -> ...
  var jointMatrixTree = foo(jointName, keyframe, jointRelationships, keyframeJointMatrices, accumulator)
  // TODO: Revisit this. Thrown in to pass tests. Maybe just return `jointMatrix`
  // when there aren't any parent matrices to factor in
  var worldMatrix = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
  jointMatrixTree.forEach(function (jointMatrix) {
    // TODO: Still not sure why we multiply in this order
    mat4Multiply(worldMatrix, worldMatrix, jointMatrix)
  })
  return worldMatrix
}

// TODO: Clean up... well.. at least it works now :sweat_smile:
function foo (jointName, keyframe, jointRelationships, keyframeJointMatrices) {
  var jointMatrix = keyframeJointMatrices[keyframe][jointName]
  var parentJointName = jointRelationships[jointName].parent
  if (parentJointName) {
    return [jointMatrix].concat(foo(parentJointName, keyframe, jointRelationships, keyframeJointMatrices))
  }
  return [jointMatrix]
}
<commit_msg>add a conditional for armatureScale in skeletal animation<commit_after>var mat4Multiply = require('gl-mat4/multiply')
var mat4Scale = require('gl-mat4/scale')
var mat4Transpose = require('gl-mat4/transpose')

module.exports = ParseLibraryAnimations

// TODO: parse interpolation
// TODO: Don't hard code attribute location
// TODO: Don't assume that joint animations are in order
// TODO: Inefficient. use depth first traversal
function ParseLibraryAnimations (library_animations, jointBindPoses, visualSceneData) {
  var animations = library_animations[0].animation
  var allKeyframes = {}
  var keyframeJointMatrices = {}
  var jointRelationships = visualSceneData.jointRelationships
  var armatureScale = visualSceneData.armatureScale

  // First pass.. get all the joint matrices
  animations.forEach(function (anim, animationIndex) {
    if (anim.$.id.indexOf('pose_matrix') !== -1) {
      // TODO: Is this the best way to get an animations joint target?
      var animatedJointName = anim.channel[0].$.target.split('/')[0]

      var currentKeyframes = anim.source[0].float_array[0]._.split(' ').map(Number)

      var currentJointPoseMatrices = anim.source[1].float_array[0]._.split(' ').map(Number)

      currentKeyframes.forEach(function (_, keyframeIndex) {
        keyframeJointMatrices[currentKeyframes[keyframeIndex]] = keyframeJointMatrices[currentKeyframes[keyframeIndex]] || {}
        var currentJointMatrix = currentJointPoseMatrices.slice(16 * keyframeIndex, 16 * keyframeIndex + 16)
        if (!jointRelationships[animatedJointName].parent) {
          // apply library visual scene transformations to top level parent joint(s)
          if (armatureScale) {
            mat4Scale(currentJointMatrix, currentJointMatrix, armatureScale)
          }
        }

        keyframeJointMatrices[currentKeyframes[keyframeIndex]][animatedJointName] = currentJointMatrix
      })
    }
  })
  // Second pass.. Calculate world matrices
  animations.forEach(function (anim, animationIndex) {
    if (anim.$.id.indexOf('pose_matrix') !== -1) {
      var animatedJointName = anim.channel[0].$.target.split('/')[0]
      var currentKeyframes = anim.source[0].float_array[0]._.split(' ').map(Number)
      currentKeyframes.forEach(function (_, keyframeIndex) {
        var currentKeyframe = currentKeyframes[keyframeIndex]
        allKeyframes[currentKeyframes[keyframeIndex]] = allKeyframes[currentKeyframe] || []

        // Multiply by parent world matrix
        var jointWorldMatrix = getParentWorldMatrix(animatedJointName, currentKeyframe, jointRelationships, keyframeJointMatrices)

        // Multiply our joint's inverse bind matrix
        mat4Multiply(jointWorldMatrix, jointBindPoses[animatedJointName], jointWorldMatrix)

        // Turn our row major matrix into a column major matrix. OpenGL uses column major
        mat4Transpose(jointWorldMatrix, jointWorldMatrix)

        // Trim to 6 significant figures (Maybe even 6 is more than needed?)
        jointWorldMatrix = jointWorldMatrix.map(function (val) {
          return parseFloat(val.toFixed(6))
        })

        allKeyframes[currentKeyframe].push(jointWorldMatrix)
      })
    }
  })

  return allKeyframes
}

// TODO: Refactor. Depth first traversal might make all of this less hacky
function getParentWorldMatrix (jointName, keyframe, jointRelationships, keyframeJointMatrices, accumulator) {
  // child -> parent -> parent -> ...
  var jointMatrixTree = foo(jointName, keyframe, jointRelationships, keyframeJointMatrices, accumulator)
  // TODO: Revisit this. Thrown in to pass tests. Maybe just return `jointMatrix`
  // when there aren't any parent matrices to factor in
  var worldMatrix = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
  jointMatrixTree.forEach(function (jointMatrix) {
    // TODO: Still not sure why we multiply in this order
    mat4Multiply(worldMatrix, worldMatrix, jointMatrix)
  })
  return worldMatrix
}

// TODO: Clean up... well.. at least it works now :sweat_smile:
function foo (jointName, keyframe, jointRelationships, keyframeJointMatrices) {
  var jointMatrix = keyframeJointMatrices[keyframe][jointName]
  var parentJointName = jointRelationships[jointName].parent
  if (parentJointName) {
    return [jointMatrix].concat(foo(parentJointName, keyframe, jointRelationships, keyframeJointMatrices))
  }
  return [jointMatrix]
}
<|endoftext|>


<commit_before>/**
 * @file Chatbot using AIML.
 * @author Capuccino
 * @author Ovyerus
 */

const burly = require('burlyy');
let natsuki;

exports.commands = ['chat'];

exports.init = () => {
    natsuki = new burly({
       defaultResponse: null,
       name:'Natsuki'
    });
    natsuki.loadDir(`${mainDir}/assets/chatbot`);
};

exports.chat = {
    desc: 'Talk to the bot',
    usage: '<message>',
    async main(bot, ctx) {
        await ctx.channel.sendTyping();

        let res = await natsuki.talk(ctx.cleanSuffix);

        await ctx.createMesage(res);
    }
};<commit_msg>Shuffle some chatbot stuff around<commit_after>/**
 * @file Chatbot using AIML.
 * @author Capuccino
 * @author Ovyerus
 */

const burly = require('burlyy');
const natsuki = new burly({
    name: 'Natsuki'
});

exports.commands = ['chat'];

exports.init = () => {
    natsuki.loadDir(`${mainDir}/assets/chatbot`);
};

exports.chat = {
    desc: 'Talk to the bot',
    usage: '<message>',
    async main(bot, ctx) {
        if (!ctx.suffix) return await ctx.createMessage('chatbot-noArgs');

        await ctx.channel.sendTyping();

        let res = await natsuki.talk(ctx.cleanSuffix);

        await ctx.createMesage(res);
    }
};<|endoftext|>


<commit_before>$( document ).ready(function() {
	var stageNum = 1;
    $( "#addStage" ).click(function() {
    		var newStage = "

Stage " + stageNum + "
Number of people <input type='number' class='people' min='0' style='width:50px'>
Rule <input type='number' class='rule' min='0' style='width:50px'>
"
        	$("#trialSim").append(newStage);
        stageNum += 1
    });
    $("#start").click(function(){
    		var values = [];
    		var peopleArray = $('.people').toArray().map(function(people) { return $(people).val(); });
    		var ruleArray = $('.rule').toArray().map(function(rule) { return $(rule).val(); });
    		var inputData = R.zip(peopleArray, ruleArray);
    });
});<commit_msg>Set up user input validation<commit_after>$( document ).ready(function() {
	var stageNum = 1;
    $( "#addStage" ).click(function() {
    		var newStage = "

Stage " + stageNum + "
Number of people <input type='number' class='people' min='0' style='width:50px'>
Rule <input type='number' class='rule' min='0' style='width:50px'>
"
        	$("#trialSim").append(newStage);
        stageNum += 1
    });
    $("#start").click(function(){
    		var values = [];
    		var peopleArray = $('.people').toArray().map(function(people) { return $(people).val(); });
    		var ruleArray = $('.rule').toArray().map(function(rule) { return $(rule).val(); });
    		var sumPeople = 0
    		for (var i = 0; i<peopleArray.length, i++){
    			if (peopleArray[i] === "" || ruleArray[i] === ""){
    				var emptyBox = true
    			}
    			sumPeople += peopleArray[i]
    			if (ruleArray[i]>sumPeople) {
    				var ruleTooBig = true
    				//alert saying that the number of people to pass is greater than the total number
    			}
    		}

    		var inputData = R.zip(peopleArray, ruleArray);
    		inputData = R.map(function (tuple) { return { numPeople: tuple[0], passThreshold: tuple[1] }; },inputData);
			//at this point, we are ready to call createGrid on inputData
			createGrid(x, [
    });
});<|endoftext|>


<commit_before>/*jslint node:true, browser:true */
'use strict';
/*
    Copyright 2015 Enigma Marketing Services Limited

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

module.exports = function (app) {
    var Directive = function (Restangular, $timeout, $q) {
        var deep = require('deep-get-set'),
            directive = {},
            pendingRequests = [],
            completeRequests = {};

        deep.p = true; //hack to create empty objects

        directive.restrict = 'A';

        directive.scope = {};

        directive.controller = function ($scope) {
            var self = this;
            // expose the local scope so it can be shared on
            // the directives that require this one
            // check directives/var.js
            self.$scope = $scope;

            self.parseName = function (name) {
                var opts = {},
                    parts = name.split('.');

                opts.name = name;
                opts.entity = parts[0];
                opts.id = parts[1];
                opts.property = parts.slice(2).join('.');

                return opts;
            };

            self.getData = function (name) {
                var opts = self.parseName(name),
                    Entity = Restangular.all(opts.entity),
                    isRequestPending = (pendingRequests.indexOf(opts.entity + '.' + opts.id) !== -1),
                    hasBeenRequested = $scope[opts.entity];

                if (!hasBeenRequested && !isRequestPending) {
                    //add to pending requests
                    pendingRequests.push(opts.entity + '.' + opts.id);

                    // get data from API
                    Entity
                        .get(opts.id)
                        .then(function (data) {
                            // remove from pending requests
                            pendingRequests.splice(pendingRequests.indexOf(opts.entity + '.' + opts.id), 1);

                            $timeout(function () {
                                $scope.$apply(function () {
                                    var value;
                                    // add the API response to the $scope
                                    deep($scope, opts.entity + '.' + opts.id, data);
                                    // cache in complete requests so we can quicly access it
                                    completeRequests[opts.entity] = $scope[opts.entity];
                                    // if the requested property is missing
                                    // create it
                                    value = deep($scope, opts.name);
                                    if (value === undefined) {
                                        deep($scope, opts.name, '');
                                    }
                                });
                            });
                        }, function (err) {
                            self.$scope.$emit('error', err);
                        });
                }

                return $scope;
            };

            self.saveAll = function () {
                var promisses = [];

                Object.keys(completeRequests).forEach(function (entity) {
                    var Entity = completeRequests[entity];

                    Object.keys(Entity).forEach(function (id) {
                        var item = Entity[id];

                        promisses.push(item.save());
                    });
                });

                $q.all(promisses).then(function (data) {
                    self.$scope.$emit('saved');
                }, function (err) {
                    self.$scope.$emit('error', err);
                });
            };

            // iterates the $scope obj and applies as get to all
            // restangular objects
            self.reloadAll = function () {
                var promisses = [];

                Object.keys(completeRequests).forEach(function (entity) {
                    var Entity = completeRequests[entity];

                    Object.keys(Entity).forEach(function (id) {
                        var item = Entity[id],
                            promise;

                        promise = item.get().then(function (data) {
                            $timeout(function () {
                                $scope.$apply(function () {
                                    // add the API response to the $scope
                                    deep($scope, entity + '.' + id, data);
                                });
                            });
                        });

                        promisses.push(promise);
                    });
                });

                $q.all(promisses).then(function (data) {
                    self.$scope.$emit('reloaded');
                }, function (err) {
                    self.$scope.$emit('error', err);
                });
            };
        };

        return directive;
    };

    app.directive('lkEdit', ['Restangular', '$timeout', '$q', Directive]);

    return app;
};<commit_msg>fix unused var (jslint)<commit_after>/*jslint node:true, browser:true */
'use strict';
/*
    Copyright 2015 Enigma Marketing Services Limited

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

module.exports = function (app) {
    var Directive = function (Restangular, $timeout, $q) {
        var deep = require('deep-get-set'),
            directive = {},
            pendingRequests = [],
            completeRequests = {};

        deep.p = true; //hack to create empty objects

        directive.restrict = 'A';

        directive.scope = {};

        directive.controller = function ($scope) {
            var self = this;
            // expose the local scope so it can be shared on
            // the directives that require this one
            // check directives/var.js
            self.$scope = $scope;

            self.parseName = function (name) {
                var opts = {},
                    parts = name.split('.');

                opts.name = name;
                opts.entity = parts[0];
                opts.id = parts[1];
                opts.property = parts.slice(2).join('.');

                return opts;
            };

            self.getData = function (name) {
                var opts = self.parseName(name),
                    Entity = Restangular.all(opts.entity),
                    isRequestPending = (pendingRequests.indexOf(opts.entity + '.' + opts.id) !== -1),
                    hasBeenRequested = $scope[opts.entity];

                if (!hasBeenRequested && !isRequestPending) {
                    //add to pending requests
                    pendingRequests.push(opts.entity + '.' + opts.id);

                    // get data from API
                    Entity
                        .get(opts.id)
                        .then(function (data) {
                            // remove from pending requests
                            pendingRequests.splice(pendingRequests.indexOf(opts.entity + '.' + opts.id), 1);

                            $timeout(function () {
                                $scope.$apply(function () {
                                    var value;
                                    // add the API response to the $scope
                                    deep($scope, opts.entity + '.' + opts.id, data);
                                    // cache in complete requests so we can quicly access it
                                    completeRequests[opts.entity] = $scope[opts.entity];
                                    // if the requested property is missing
                                    // create it
                                    value = deep($scope, opts.name);
                                    if (value === undefined) {
                                        deep($scope, opts.name, '');
                                    }
                                });
                            });
                        }, function (err) {
                            self.$scope.$emit('error', err);
                        });
                }

                return $scope;
            };

            self.saveAll = function () {
                var promisses = [];

                Object.keys(completeRequests).forEach(function (entity) {
                    var Entity = completeRequests[entity];

                    Object.keys(Entity).forEach(function (id) {
                        var item = Entity[id];

                        promisses.push(item.save());
                    });
                });

                $q.all(promisses).then(function () {
                    self.$scope.$emit('saved');
                }, function (err) {
                    self.$scope.$emit('error', err);
                });
            };

            // iterates the $scope obj and applies as get to all
            // restangular objects
            self.reloadAll = function () {
                var promisses = [];

                Object.keys(completeRequests).forEach(function (entity) {
                    var Entity = completeRequests[entity];

                    Object.keys(Entity).forEach(function (id) {
                        var item = Entity[id],
                            promise;

                        promise = item.get().then(function (data) {
                            $timeout(function () {
                                $scope.$apply(function () {
                                    // add the API response to the $scope
                                    deep($scope, entity + '.' + id, data);
                                });
                            });
                        });

                        promisses.push(promise);
                    });
                });

                $q.all(promisses).then(function () {
                    self.$scope.$emit('reloaded');
                }, function (err) {
                    self.$scope.$emit('error', err);
                });
            };
        };

        return directive;
    };

    app.directive('lkEdit', ['Restangular', '$timeout', '$q', Directive]);

    return app;
};<|endoftext|>


<commit_before>import createBehaviorSubject from 'observable-utils/lib/createBehaviorSubject'

// Make a selector on a ReduxComponentInstance into an ES7 Observable.
export default function makeSelectorObservable(componentInstance, selector) {
	var observerCount = 0
	var subscription = undefined
	var lastSeenValue = undefined

	// Make the selector a Subject.
	var subj = createBehaviorSubject({
		onObserversChanged: function(observers) {
			observerCount = observers.length
			if (observerCount === 0) {
				// No subscribers left; remove upstream subscription.
				if(subscription) subscription.unsubscribe()
				subscription = undefined
			} else if (observerCount === 1) {
				// This closure will observe and select from the store.
				// Selectors expect to receive valid states, not undefined, so only call
				// the selector when the state is fully realized.
				var observeState = function() {
					var store = componentInstance.store
					if (!store) return
					var state = store.getState()
					if (state !== undefined) {
						var val = selector(state)
						if (val !== lastSeenValue) { lastSeenValue = val; subj.next(val) }
					}
				}

				subscription = componentInstance.__getSubject().subscribe({ next: observeState })
				observeState()
			}
		}
	})
	Object.assign(selector, subj)

	return selector
}
<commit_msg>[redux-components] Fix extraneous subscription bug<commit_after>import createBehaviorSubject from 'observable-utils/lib/createBehaviorSubject'

// Make a selector on a ReduxComponentInstance into an ES7 Observable.
export default function makeSelectorObservable(componentInstance, selector) {
	var observerCount = 0
	var subscription = undefined
	var lastSeenValue = undefined

	// Make the selector a Subject.
	var subj = createBehaviorSubject({
		onObserversChanged: function(observers, observerAdded) {
			observerCount = observers.length
			if (observerCount === 0) {
				// No subscribers left; remove upstream subscription.
				if(subscription) subscription.unsubscribe()
				subscription = undefined
			} else if (observerCount === 1 && observerAdded) {
				// This closure will observe and select from the store.
				// Selectors expect to receive valid states, not undefined, so only call
				// the selector when the state is fully realized.
				var observeState = function() {
					var store = componentInstance.store
					if (!store) return
					var state = store.getState()
					if (state !== undefined) {
						var val = selector(state)
						if (val !== lastSeenValue) { lastSeenValue = val; subj.next(val) }
					}
				}

				subscription = componentInstance.__getSubject().subscribe({ next: observeState })
				observeState()
			}
		}
	})
	Object.assign(selector, subj)

	return selector
}
<|endoftext|>


<commit_before>const glob = require('glob');
const fs = require('fs');
const path = require('path');
const marked = require('marked');
const renderer = new marked.Renderer();
const formatDate = require('date-fns/format');
const camelCase = require('camel-case');
const titleCase = require('title-case');
const shell = require('shelljs');
const getFileNameFromPath = require('@lukeboyle/get-filename-from-path');

renderer.heading = function(code, level) {
	if (level === 1) {
		return `

${code}

		`;
	} else {
		return `<h${level}>${code}</h${level}>`;
	}
};

renderer.code = function(code, language) {
	return `

		${code.split('\n').map(codeBlock => {
		const codeWithEscapedQuotes = codeBlock.split('"').join('\\"');
		const codeWithEscapedHashes = codeWithEscapedQuotes.split('#').join('\\#');
		return `<div>{"${codeWithEscapedHashes}"}</div>`;
	}).join('')}

`;
};

renderer.table = function(header, body) {
	if (header.includes('Metadata name')) {
		const rows = body.split('
');
		const dateRow = rows.find(row => row.includes('post_date'));
		const rawDate = dateRow.split('')[2];
		const date = rawDate.slice(0, rawDate.length - 12);
		return `

			<time datetime="${date}">${formatDate(date, 'Do of MMMM, YYYY')}</time>

`
	} else {
		return header + body;
	}
};

renderer.image = function(href, title, text) {
	return `<img src="${href}" alt="${text}"/>`;
};

function getMarkupFromMarkdown(markdownString) {
	return marked(markdownString, {renderer: renderer, gfm: true});
}

function generateComponent(acc, curr, index) {
	const fileName = getFileNameFromPath(curr.path);
	const camelCaseName = camelCase(fileName);
	const postContents = curr.contents;

	// TODO: use regex
	const postStatusIndex = postContents.indexOf('post_status');
	const almostPostStatus = postContents.slice(postStatusIndex + 13);
	const postStatus = almostPostStatus.slice(0, almostPostStatus.indexOf('|')).trim();

	const lines = postContents.split('\n');
	// TODO: fuck this off
	let tableMode = false;
	const contents = lines.reduce((acc, curr, index) => {
		if (curr.slice(0, 2) === '# ') {
			return Object.assign({}, acc, {
				title: curr.slice(2)
			});
		}

		// Table Start
		if (curr.includes('| Metadata name |')) {
			tableMode = true;
		}

		if (tableMode === true) {
			if (curr.slice(0, 2) === '| ') {
				const lineWithoutFirstDelimeter = curr.slice(2);
				const key = lineWithoutFirstDelimeter.slice(0, lineWithoutFirstDelimeter.indexOf(' | '));
				const value = lineWithoutFirstDelimeter.slice(lineWithoutFirstDelimeter.indexOf(' | ') + 3, -2);

				return Object.assign({}, acc, {
					metaData: Object.assign({}, acc.metaData, {
						[key]: value
					})
				});
			} else {
				tableMode = false;
			}
		}

		return Object.assign({}, acc, {
			contents: `${acc.contents || ''}\n${curr}`
		})
	}, {});

	if (postStatus !== 'draft') {
		acc.push({
			path: curr.path,
			fileName,
			componentName: camelCaseName[0].toUpperCase() + camelCaseName.slice(1),
			component: `
			import React from 'react';
			import BlogPost from '../../../../components/blog-post.jsx';

			export default class ${camelCaseName} extends React.Component {
				render() {
					return (
						<BlogPost
							isSinglePostPage={!this.props.isBlogPage}
							title="${contents.title}"
							publishDate="${contents.metaData['post_date']}"
							slug="${curr.path.replace('.md', '')}"
						>
							${getMarkupFromMarkdown(contents.contents)}
						</BlogPost>
					);
				}
			}
		`
		});
	}

	return acc;
}

(() => {
	glob('blog-posts/**/*.md', {}, (err, files) => {
		const blogPosts = files.reduce((acc, curr) => {
			acc.push({
				path: curr,
				contents: fs.readFileSync(curr, {encoding: 'utf-8'})
			});

			return acc;
		}, []);

		const reversedComponents = blogPosts.reduce(generateComponent, []);

		shell.rm('-rf', path.resolve(`${__dirname}/../src/pages/blog-posts`));

		reversedComponents.forEach(component => {
			shell.mkdir('-p', path.resolve(`${__dirname}/../src/pages/${component.path.replace(`/${component.fileName}.md`, '')}`));
			fs.writeFileSync(path.resolve(`${__dirname}/../src/pages/${component.path.replace('.md', '.jsx')}`), component.component);
		});

		const components = reversedComponents.reverse();
		const postsPerPage = 4;
		const pages = components.reduce((acc, curr, index) => {
			const pagesSoFar = Object.keys(acc);

			const lastPage = parseInt(pagesSoFar[pagesSoFar.length - 1], 10) || 0;

			if (index % postsPerPage === 0) {
				const newPage = lastPage + 1;

				return Object.assign(
					{},
					acc,
					{
						[newPage]: [
							curr
						]
					}
				);
			}

			return Object.assign(
				{},
				acc,
				{
					[lastPage]: [
						...acc[lastPage],
						curr
					]
				}
			);
		}, {});

		Object.entries(pages).forEach(([key, value], index) => {
			const blogPage = `
			import React from 'react';
			import Helmet from 'react-helmet';
			${value.reduce((acc, curr) => {
				return acc + `import ${curr.componentName} from '${index === 0 ? './' : '../'}${curr.path.replace('.md', '.jsx')}';\n`;
			}, '')}

			export default class Blog extends React.Component {
				render() {
					return (

							<Helmet>
								<title>${index === 0 ? 'Blog | Luke Boyle' : `Page ${parseInt(key, 10) - 1} | Blog`}</title>
							</Helmet>

									Boyleing Point

									7/11 was an inside job

								${value.reduce((acc, curr) => {
				return acc + `<${curr.componentName} isBlogPage={true}/>\n`;
			}, '')}

									${index > 0 ? `<li><a href="${key === '2' ? '/blog' : `/blog/${parseInt(key, 10) - 2}`}">Newer</a></li>` : ''}
									${index !== Object.values(pages).length - 1 ? `<li className="pagination__next"><a href="/blog/${parseInt(key, 10)}">Older</a></li>` : ''}

					);
				}
			}
		`;

			const fileName = index === 0
				? `${__dirname}/../src/pages/blog.jsx`
				: `${__dirname}/../src/pages/blog/${index}.jsx`;

			fs.writeFileSync(path.resolve(fileName), blogPage);
		});
	});
})();<commit_msg>fix: not linking correctly to blog posts<commit_after>const glob = require('glob');
const fs = require('fs');
const path = require('path');
const marked = require('marked');
const renderer = new marked.Renderer();
const formatDate = require('date-fns/format');
const camelCase = require('camel-case');
const titleCase = require('title-case');
const shell = require('shelljs');
const getFileNameFromPath = require('@lukeboyle/get-filename-from-path');

renderer.heading = function(code, level) {
	if (level === 1) {
		return `

${code}

		`;
	} else {
		return `<h${level}>${code}</h${level}>`;
	}
};

renderer.code = function(code, language) {
	return `

		${code.split('\n').map(codeBlock => {
		const codeWithEscapedQuotes = codeBlock.split('"').join('\\"');
		const codeWithEscapedHashes = codeWithEscapedQuotes.split('#').join('\\#');
		return `<div>{"${codeWithEscapedHashes}"}</div>`;
	}).join('')}

`;
};

renderer.table = function(header, body) {
	if (header.includes('Metadata name')) {
		const rows = body.split('
');
		const dateRow = rows.find(row => row.includes('post_date'));
		const rawDate = dateRow.split('')[2];
		const date = rawDate.slice(0, rawDate.length - 12);
		return `

			<time datetime="${date}">${formatDate(date, 'Do of MMMM, YYYY')}</time>

`
	} else {
		return header + body;
	}
};

renderer.image = function(href, title, text) {
	return `<img src="${href}" alt="${text}"/>`;
};

function getMarkupFromMarkdown(markdownString) {
	return marked(markdownString, {renderer: renderer, gfm: true});
}

function generateComponent(acc, curr, index) {
	const fileName = getFileNameFromPath(curr.path);
	const camelCaseName = camelCase(fileName);
	const postContents = curr.contents;

	// TODO: use regex
	const postStatusIndex = postContents.indexOf('post_status');
	const almostPostStatus = postContents.slice(postStatusIndex + 13);
	const postStatus = almostPostStatus.slice(0, almostPostStatus.indexOf('|')).trim();

	const lines = postContents.split('\n');
	// TODO: fuck this off
	let tableMode = false;
	const contents = lines.reduce((acc, curr, index) => {
		if (curr.slice(0, 2) === '# ') {
			return Object.assign({}, acc, {
				title: curr.slice(2)
			});
		}

		// Table Start
		if (curr.includes('| Metadata name |')) {
			tableMode = true;
		}

		if (tableMode === true) {
			if (curr.slice(0, 2) === '| ') {
				const lineWithoutFirstDelimeter = curr.slice(2);
				const key = lineWithoutFirstDelimeter.slice(0, lineWithoutFirstDelimeter.indexOf(' | '));
				const value = lineWithoutFirstDelimeter.slice(lineWithoutFirstDelimeter.indexOf(' | ') + 3, -2);

				return Object.assign({}, acc, {
					metaData: Object.assign({}, acc.metaData, {
						[key]: value
					})
				});
			} else {
				tableMode = false;
			}
		}

		return Object.assign({}, acc, {
			contents: `${acc.contents || ''}\n${curr}`
		})
	}, {});

	if (postStatus !== 'draft') {
		acc.push({
			path: curr.path,
			fileName,
			componentName: camelCaseName[0].toUpperCase() + camelCaseName.slice(1),
			component: `
			import React from 'react';
			import BlogPost from '../../../../components/blog-post.jsx';

			export default class ${camelCaseName} extends React.Component {
				render() {
					return (
						<BlogPost
							isSinglePostPage={!this.props.isBlogPage}
							title="${contents.title}"
							publishDate="${contents.metaData['post_date']}"
							slug="/${curr.path.replace('.md', '')}"
						>
							${getMarkupFromMarkdown(contents.contents)}
						</BlogPost>
					);
				}
			}
		`
		});
	}

	return acc;
}

(() => {
	glob('blog-posts/**/*.md', {}, (err, files) => {
		const blogPosts = files.reduce((acc, curr) => {
			acc.push({
				path: curr,
				contents: fs.readFileSync(curr, {encoding: 'utf-8'})
			});

			return acc;
		}, []);

		const reversedComponents = blogPosts.reduce(generateComponent, []);

		shell.rm('-rf', path.resolve(`${__dirname}/../src/pages/blog-posts`));

		reversedComponents.forEach(component => {
			shell.mkdir('-p', path.resolve(`${__dirname}/../src/pages/${component.path.replace(`/${component.fileName}.md`, '')}`));
			fs.writeFileSync(path.resolve(`${__dirname}/../src/pages/${component.path.replace('.md', '.jsx')}`), component.component);
		});

		const components = reversedComponents.reverse();
		const postsPerPage = 4;
		const pages = components.reduce((acc, curr, index) => {
			const pagesSoFar = Object.keys(acc);

			const lastPage = parseInt(pagesSoFar[pagesSoFar.length - 1], 10) || 0;

			if (index % postsPerPage === 0) {
				const newPage = lastPage + 1;

				return Object.assign(
					{},
					acc,
					{
						[newPage]: [
							curr
						]
					}
				);
			}

			return Object.assign(
				{},
				acc,
				{
					[lastPage]: [
						...acc[lastPage],
						curr
					]
				}
			);
		}, {});

		Object.entries(pages).forEach(([key, value], index) => {
			const blogPage = `
			import React from 'react';
			import Helmet from 'react-helmet';
			${value.reduce((acc, curr) => {
				return acc + `import ${curr.componentName} from '${index === 0 ? './' : '../'}${curr.path.replace('.md', '.jsx')}';\n`;
			}, '')}

			export default class Blog extends React.Component {
				render() {
					return (

							<Helmet>
								<title>${index === 0 ? 'Blog | Luke Boyle' : `Page ${parseInt(key, 10) - 1} | Blog`}</title>
							</Helmet>

									Boyleing Point

									7/11 was an inside job

								${value.reduce((acc, curr) => {
				return acc + `<${curr.componentName} isBlogPage={true}/>\n`;
			}, '')}

									${index > 0 ? `<li><a href="${key === '2' ? '/blog' : `/blog/${parseInt(key, 10) - 2}`}">Newer</a></li>` : ''}
									${index !== Object.values(pages).length - 1 ? `<li className="pagination__next"><a href="/blog/${parseInt(key, 10)}">Older</a></li>` : ''}

					);
				}
			}
		`;

			const fileName = index === 0
				? `${__dirname}/../src/pages/blog.jsx`
				: `${__dirname}/../src/pages/blog/${index}.jsx`;

			fs.writeFileSync(path.resolve(fileName), blogPage);
		});
	});
})();<|endoftext|>


<commit_before>import React, { PropTypes } from 'react'
import Faux from 'react-faux-dom'
import * as d3 from 'd3'
import styled from 'styled-components'

const { arrayOf, array, string, number, func } = PropTypes

const BarChart = React.createClass({
  mixins: [Faux.mixins.core, Faux.mixins.anim],
  propTypes: {
    data: arrayOf(array),
    xDomain: array,
    colors: arrayOf(string),
    className: string,
    xLabel: string,
    yLabel: string,
    width: number,
    height: number,
    hover: string,
    setHover: func
  },
  getInitialState () {
    return {
      look: 'stacked',
      chart: 'loading...'
    }
  },
  componentDidMount () {
    this.renderD3(true)
  },
  componentDidUpdate (prevProps, prevState) {
    if (this.props !== prevProps) {
      this.renderD3(false)
    }
  },
  render () {
    return (

        <button onClick={this.toggle}>Toggle</button>
        {this.state.chart}

    )
  },
  toggle () {
    if (this.state.look === 'stacked') {
      this.setState({ look: 'grouped' })
      this.transitionGrouped()
    } else {
      this.setState({ look: 'stacked' })
      this.transitionStacked()
    }
  },
  renderD3 (firstRender) {
    const n = this.props.data.length // number of layers
    const stack = d3.layout.stack()
    const layers = stack(this.props.data)
    const yStackMax = d3.max(layers, layer => d3.max(layer, d => d.y0 + d.y))
    const margin = { top: 20, right: 10, bottom: 50, left: 50 }
    const width = this.props.width - margin.left - margin.right
    const height = this.props.height - margin.top - margin.bottom
    const x = d3.scale.ordinal().domain(this.props.xDomain).rangeRoundBands([0, width], 0.08)
    const y = d3.scale.linear().domain([0, yStackMax]).range([height, 0])
    const color = d3.scale.linear().domain([0, n - 1]).range(this.props.colors)
    const xAxis = d3.svg.axis().scale(x).orient('bottom')
    const yAxis = d3.svg.axis().scale(y).orient('left')

    // create a faux div and store its virtual DOM in state.chart
    let faux = this.connectFauxDOM('div', 'chart')

    let svg = firstRender
      ? d3
          .select(faux)
          .append('svg')
          .attr('class', this.props.className)
          .attr('width', width + margin.left + margin.right)
          .attr('height', height + margin.top + margin.bottom)
          .append('g')
          .attr('transform', `translate(${margin.left}, ${margin.top})`)
      : d3.select(faux).select('svg').select('g')

    let layer = svg.selectAll('.layer').data(layers)
    layer.enter().append('g').attr('class', 'layer').style('fill', (d, i) => color(i))

    let rect = layer.selectAll('rect').data(d => d)
    rect.classed('disabled', d => this.props.hover && d.x !== this.props.hover)
    rect
      .enter()
      .append('rect')
      .attr('x', d => x(d.x))
      .attr('y', height)
      .attr('width', x.rangeBand())
      .attr('height', 0)
      .on('mouseover', d => this.props.setHover(d.x))
      .on('mouseout', d => this.props.setHover(null))
    if (this.state.look === 'stacked') {
      rect
        .transition()
        .delay((d, i) => i * 10)
        .attr('y', d => y(d.y0 + d.y))
        .attr('height', d => y(d.y0) - y(d.y0 + d.y))
    } else {
      rect.transition().delay((d, i) => i * 10).attr('y', d => y(d.y)).attr('height', d => height - y(d.y))
    }
    this.animateFauxDOM(800)

    if (firstRender) {
      svg.append('g').attr('class', 'x axis').attr('transform', `translate(0, ${height})`).call(xAxis)
      svg
        .append('text')
        .attr('transform', `translate(${width / 2} ,${height + margin.bottom - 5})`)
        .style('text-anchor', 'middle')
        .text(this.props.xLabel)

      svg.append('g').attr('class', 'y axis').attr('transform', 'translate(0, 0)').call(yAxis)
      svg
        .append('text')
        .attr('transform', 'rotate(-90)')
        .attr('y', 0 - margin.left)
        .attr('x', 0 - height / 2)
        .attr('dy', '1em')
        .style('text-anchor', 'middle')
        .text(this.props.yLabel)
    } else {
      svg.select('g.x.axis').call(xAxis)
      svg.select('g.y.axis').call(yAxis)
    }

    this.transitionGrouped = () => {
      rect
        .transition()
        .duration(500)
        // .delay((d, i) => i * 10)
        .attr('x', (d, i, j) => x(d.x) + x.rangeBand() / n * j)
        .attr('width', x.rangeBand() / n)
        .transition()
        .attr('y', d => y(d.y))
        .attr('height', d => height - y(d.y))
      this.animateFauxDOM(2000)
    }

    this.transitionStacked = () => {
      rect
        .transition()
        .duration(500)
        // .delay((d, i) => i * 10)
        .attr('y', d => y(d.y0 + d.y))
        .attr('height', d => y(d.y0) - y(d.y0 + d.y))
        .transition()
        .attr('x', d => x(d.x))
        .attr('width', x.rangeBand())
      this.animateFauxDOM(2000)
    }
  }
})

const StyledBarChart = styled(BarChart)`
  .x.axis line,
  .x.axis path,
  .y.axis line,
  .y.axis path {
    fill: none;
    stroke: #000;
  }
  rect.disabled {
    opacity: 0.3;
  }
`

export default StyledBarChart
<commit_msg>add d3 tooltip<commit_after>import React, { PropTypes } from 'react'
import Faux from 'react-faux-dom'
import * as d3 from 'd3'
import styled from 'styled-components'
import _ from 'lodash'

const { arrayOf, array, string, number, func } = PropTypes

const BarChart = React.createClass({
  mixins: [Faux.mixins.core, Faux.mixins.anim],
  propTypes: {
    data: arrayOf(array),
    xDomain: array,
    colors: arrayOf(string),
    className: string,
    xLabel: string,
    yLabel: string,
    width: number,
    height: number,
    hover: string,
    setHover: func
  },
  getInitialState () {
    return {
      look: 'stacked',
      chart: 'loading...'
    }
  },
  componentDidMount () {
    this.renderD3(true)
  },
  componentDidUpdate (prevProps, prevState) {
    if (this.props !== prevProps) {
      this.renderD3(false)
    }
  },
  render () {
    return (

        <button onClick={this.toggle}>Toggle</button>
        {this.state.chart}

    )
  },
  toggle () {
    if (this.state.look === 'stacked') {
      this.setState({ look: 'grouped' })
      this.transitionGrouped()
    } else {
      this.setState({ look: 'stacked' })
      this.transitionStacked()
    }
  },
  renderD3 (firstRender) {
    const n = this.props.data.length // number of layers
    const stack = d3.layout.stack()
    const layers = stack(this.props.data)
    const yStackMax = d3.max(layers, layer => d3.max(layer, d => d.y0 + d.y))
    const margin = { top: 20, right: 10, bottom: 50, left: 50 }
    const width = this.props.width - margin.left - margin.right
    const height = this.props.height - margin.top - margin.bottom
    const x = d3.scale.ordinal().domain(this.props.xDomain).rangeRoundBands([0, width], 0.08)
    const y = d3.scale.linear().domain([0, yStackMax]).range([height, 0])
    const color = d3.scale.linear().domain([0, n - 1]).range(this.props.colors)
    const xAxis = d3.svg.axis().scale(x).orient('bottom')
    const yAxis = d3.svg.axis().scale(y).orient('left')

    // create a faux div and store its virtual DOM in state.chart
    let faux = this.connectFauxDOM('div', 'chart')

    let svg = firstRender
      ? d3
          .select(faux)
          .append('svg')
          .attr('class', this.props.className)
          .attr('width', width + margin.left + margin.right)
          .attr('height', height + margin.top + margin.bottom)
          .append('g')
          .attr('transform', `translate(${margin.left}, ${margin.top})`)
      : d3.select(faux).select('svg').select('g')

    let layer = svg.selectAll('.layer').data(layers)
    layer.enter().append('g').attr('class', 'layer').style('fill', (d, i) => color(i))

    let rect = layer.selectAll('rect').data(d => d)
    rect.classed('disabled', d => this.props.hover && d.x !== this.props.hover)
    rect
      .enter()
      .append('rect')
      .attr('x', d => x(d.x))
      .attr('y', height)
      .attr('width', x.rangeBand())
      .attr('height', 0)
      .on('mouseover', d => this.props.setHover(d.x))
      .on('mouseout', d => this.props.setHover(null))
    if (this.state.look === 'stacked') {
      rect
        .transition()
        .delay((d, i) => i * 10)
        .attr('y', d => y(d.y0 + d.y))
        .attr('height', d => y(d.y0) - y(d.y0 + d.y))
    } else {
      rect.transition().delay((d, i) => i * 10).attr('y', d => y(d.y)).attr('height', d => height - y(d.y))
    }
    this.animateFauxDOM(800)

    let tooltip = firstRender
      ? d3
          .select(faux)
          .append('div')
          .attr('class', 'tooltip')
          .style('position', 'absolute')
          .style('z-index', '10')
          .style('display', 'inline-block')
          .style('border', 'solid grey 1px')
          .style('border-radius', '2px')
          .style('padding', '5px')
          .style('color', 'grey')
      : d3.select(faux).select('.tooltip')
    if (this.props.hover !== null) {
      const hoveredData = this.props.data.map(l => _.find(l, { x: this.props.hover }))
      const top = this.state.look === 'stacked' ? arr => y(_.sum(arr)) : arr => y(_.max(arr))
      tooltip
        .style('visibility', 'visible')
        .style('left', x(this.props.hover) + 40)
        .style('top', top(_.map(hoveredData, 'y')) + margin.top - 15)
        .html(`${this.props.hover}: ${_.map(hoveredData, 'y').join(', ')}`)
    } else {
      tooltip.style('visibility', 'hidden')
    }

    if (firstRender) {
      svg.append('g').attr('class', 'x axis').attr('transform', `translate(0, ${height})`).call(xAxis)
      svg
        .append('text')
        .attr('transform', `translate(${width / 2} ,${height + margin.bottom - 5})`)
        .style('text-anchor', 'middle')
        .text(this.props.xLabel)

      svg.append('g').attr('class', 'y axis').attr('transform', 'translate(0, 0)').call(yAxis)
      svg
        .append('text')
        .attr('transform', 'rotate(-90)')
        .attr('y', 0 - margin.left)
        .attr('x', 0 - height / 2)
        .attr('dy', '1em')
        .style('text-anchor', 'middle')
        .text(this.props.yLabel)
    } else {
      svg.select('g.x.axis').call(xAxis)
      svg.select('g.y.axis').call(yAxis)
    }

    this.transitionGrouped = () => {
      rect
        .transition()
        .duration(500)
        // .delay((d, i) => i * 10)
        .attr('x', (d, i, j) => x(d.x) + x.rangeBand() / n * j)
        .attr('width', x.rangeBand() / n)
        .transition()
        .attr('y', d => y(d.y))
        .attr('height', d => height - y(d.y))
      this.animateFauxDOM(2000)
    }

    this.transitionStacked = () => {
      rect
        .transition()
        .duration(500)
        // .delay((d, i) => i * 10)
        .attr('y', d => y(d.y0 + d.y))
        .attr('height', d => y(d.y0) - y(d.y0 + d.y))
        .transition()
        .attr('x', d => x(d.x))
        .attr('width', x.rangeBand())
      this.animateFauxDOM(2000)
    }
  }
})

const StyledBarChart = styled(BarChart)`
  .x.axis line,
  .x.axis path,
  .y.axis line,
  .y.axis path {
    fill: none;
    stroke: #000;
  }
  rect.disabled {
    opacity: 0.3;
  }
`

export default StyledBarChart
<|endoftext|>


<commit_before>goog.provide('gmf.AbstractDesktopController');

goog.require('gmf');
goog.require('gmf.AbstractController');
/** @suppress {extraRequire} */
goog.require('ngeo.bboxQueryDirective');
/** @suppress {extraRequire} */
goog.require('gmf.contextualdataDirective');
/** @suppress {extraRequire} */
goog.require('gmf.contextualdatacontentDirective');
/** @suppress {extraRequire} */
goog.require('gmf.displayquerygridComponent');
/** @suppress {extraRequire} */
goog.require('gmf.drawfeatureDirective');
/** @suppress {extraRequire} */
goog.require('gmf.editfeatureselectorDirective');
/** @suppress {extraRequire} */
goog.require('gmf.elevationDirective');
/** @suppress {extraRequire} */
goog.require('gmf.filterselectorComponent');
/** @suppress {extraRequire} */
goog.require('gmf.mousepositionComponent');
/** @suppress {extraRequire} */
goog.require('gmf.printDirective');
/** @suppress {extraRequire} */
goog.require('gmf.profileComponent');
/** @suppress {extraRequire} */
goog.require('gmf.drawprofilelineDirective');
/** @suppress {extraRequire} */
goog.require('ngeo.DatePickerDirective');
/** @suppress {extraRequire} */
goog.require('gmf.TimeSliderDirective');
/** @suppress {extraRequire} */
goog.require('gmf.shareDirective');
/** @suppress {extraRequire} */
goog.require('ngeo.btngroupDirective');
/** @suppress {extraRequire} */
goog.require('ngeo.resizemapDirective');
/** @suppress {extraRequire} */
goog.require('ngeo.FeatureHelper');
/** @suppress {extraRequire} */
goog.require('ngeo.Features');
/** @suppress {extraRequire} */
goog.require('ngeo.FeatureOverlay');
/** @suppress {extraRequire} */
goog.require('ngeo.FeatureOverlayMgr');
/** @suppress {extraRequire} */
goog.require('ngeo.ScaleselectorOptions');
/** @suppress {extraRequire} */
goog.require('ngeo.scaleselectorDirective');
goog.require('ngeo.ToolActivate');
goog.require('ngeo.ToolActivateMgr');
goog.require('ol.Collection');
goog.require('ol.Map');
goog.require('ol.View');
goog.require('ol.control.ScaleLine');
goog.require('ol.control.Zoom');
goog.require('ol.interaction');
goog.require('ol.layer.Vector');
goog.require('ol.source.Vector');
goog.require('ol.style.Fill');
goog.require('ol.style.Stroke');
goog.require('ol.style.Style');
goog.require('ol.style.Text');

gmf.module.value('isDesktop', true);

/** @suppress {extraRequire} */
goog.require('ngeo.sortableDirective');
/** @suppress {extraRequire} */
goog.require('ngeo.SortableOptions');

gmf.module.value('ngeoQueryOptions', {
  'limit': 20
});

/**
 * Desktop application abstract controller.
 *
 * This file includes `goog.require`'s for desktop components/directives used
 * by the HTML page and the controller to provide the configuration.
 *
 * @param {gmfx.Config} config A part of the application config.
 * @param {angular.Scope} $scope Scope.
 * @param {angular.$injector} $injector Main injector.
 * @constructor
 * @extends {gmf.AbstractController}
 * @ngdoc controller
 * @ngInject
 * @export
 */
gmf.AbstractDesktopController = function(config, $scope, $injector) {

  const viewConfig = {
    projection: ol.proj.get(`EPSG:${config.srid || 21781}`)
  };
  ol.obj.assign(viewConfig, config.mapViewConfig || {});

  /**
   * @type {ol.Map}
   * @export
   */
  this.map = new ol.Map({
    layers: [],
    view: new ol.View(viewConfig),
    controls: config.mapControls || [
      new ol.control.ScaleLine({
        target: document.getElementById('scaleline')
      }),
      new ol.control.Zoom({
        zoomInTipLabel: '',
        zoomOutTipLabel: ''
      })
    ],
    interactions: config.mapInteractions || ol.interaction.defaults({
      pinchRotate: false,
      altShiftDragRotate: false
    }),
    loadTilesWhileAnimating: true,
    loadTilesWhileInteracting: true
  });

  /**
   * @type {boolean}
   * @export
   */
  this.loginActive = false;

  /**
   * @type {boolean}
   * @export
   */
  this.toolsActive = false;

  /**
   * @type {boolean}
   * @export
   */
  this.modalShareShown = false;

  /**
   * @type {boolean}
   * @export
   */
  this.filterSelectorActive = false;

  /**
   * @type {boolean}
   * @export
   */
  this.editFeatureActive = false;

  /**
   * @type {boolean}
   * @export
   */
  this.googleStreetViewActive = false;

  /**
   * @type {!ol.style.Style}
   * @export
   */
  this.googleStreetViewStyle = new ol.style.Style({
    text: new ol.style.Text({
      fill: new ol.style.Fill({color: '#279B61'}),
      font: 'normal 30px FontAwesome',
      offsetY: -15,
      stroke: new ol.style.Stroke({color: '#ffffff', width: 3}),
      text: '\uf041'
    })
  });

  const body = $('body');

  // initialize tooltips
  body.tooltip({
    container: 'body',
    trigger: 'hover',
    selector: '[data-toggle="tooltip"]'
  });

  // deactivate tooltips on touch device
  body.on('touchstart.detectTouch', () => {
    body.tooltip('destroy');
    body.off('touchstart.detectTouch');
  });

  /**
   * Collection of features for the draw interaction
   * @type {ol.Collection.<ol.Feature>}
   */
  const ngeoFeatures = $injector.get('ngeoFeatures');

  /**
   * @type {ngeo.FeatureOverlay}
   * @export
   */
  this.drawFeatureLayer = $injector.get('ngeoFeatureOverlayMgr')
    .getFeatureOverlay();
  this.drawFeatureLayer.setFeatures(ngeoFeatures);

  const ngeoFeatureHelper = $injector.get('ngeoFeatureHelper');

  /**
   * @type {ol.layer.Vector}
   * @export
   */
  this.editFeatureVectorLayer = new ol.layer.Vector({
    source: new ol.source.Vector({
      wrapX: false,
      features: new ol.Collection()
    }),
    style(feature, resolution) {
      return ngeoFeatureHelper.createEditingStyles(feature);
    }
    // style: ngeoFeatureHelper.createEditingStyles.bind(ngeoFeatureHelper)
  });
  this.editFeatureVectorLayer.setMap(this.map);

  /**
   * The ngeo ToolActivate manager service.
   * @type {ngeo.ToolActivateMgr}
   */
  const ngeoToolActivateMgr = $injector.get('ngeoToolActivateMgr');

  const editFeatureActivate = new ngeo.ToolActivate(this, 'editFeatureActive');
  ngeoToolActivateMgr.registerTool('mapTools', editFeatureActivate, false);

  const googleStreetViewActivate = new ngeo.ToolActivate(
    this,
    'googleStreetViewActive'
  );
  ngeoToolActivateMgr.registerTool('mapTools', googleStreetViewActivate, false);

  /**
   * @type {ngeo.ScaleselectorOptions}
   * @export
   */
  this.scaleSelectorOptions = {
    'dropup': true
  };

  /**
   * @type {ol.geom.LineString}
   * @export
   */
  this.profileLine = null;

  gmf.AbstractController.call(this, config, $scope, $injector);

  // close the login panel on successful login
  $scope.$watch(() => this.gmfUser.username, (newVal) => {
    if (newVal !== null && this.loginActive) {
      this.loginActive = false;
    }
  });

};
ol.inherits(gmf.AbstractDesktopController, gmf.AbstractController);

gmf.module.controller(
  'AbstractDesktopController',
  gmf.AbstractDesktopController);
<commit_msg>Set default decimals and precision values for drawing<commit_after>goog.provide('gmf.AbstractDesktopController');

goog.require('gmf');
goog.require('gmf.AbstractController');
/** @suppress {extraRequire} */
goog.require('ngeo.bboxQueryDirective');
/** @suppress {extraRequire} */
goog.require('gmf.contextualdataDirective');
/** @suppress {extraRequire} */
goog.require('gmf.contextualdatacontentDirective');
/** @suppress {extraRequire} */
goog.require('gmf.displayquerygridComponent');
/** @suppress {extraRequire} */
goog.require('gmf.drawfeatureDirective');
/** @suppress {extraRequire} */
goog.require('gmf.editfeatureselectorDirective');
/** @suppress {extraRequire} */
goog.require('gmf.elevationDirective');
/** @suppress {extraRequire} */
goog.require('gmf.filterselectorComponent');
/** @suppress {extraRequire} */
goog.require('gmf.mousepositionComponent');
/** @suppress {extraRequire} */
goog.require('gmf.printDirective');
/** @suppress {extraRequire} */
goog.require('gmf.profileComponent');
/** @suppress {extraRequire} */
goog.require('gmf.drawprofilelineDirective');
/** @suppress {extraRequire} */
goog.require('ngeo.DatePickerDirective');
/** @suppress {extraRequire} */
goog.require('gmf.TimeSliderDirective');
/** @suppress {extraRequire} */
goog.require('gmf.shareDirective');
/** @suppress {extraRequire} */
goog.require('ngeo.btngroupDirective');
/** @suppress {extraRequire} */
goog.require('ngeo.resizemapDirective');
/** @suppress {extraRequire} */
goog.require('ngeo.FeatureHelper');
/** @suppress {extraRequire} */
goog.require('ngeo.Features');
/** @suppress {extraRequire} */
goog.require('ngeo.FeatureOverlay');
/** @suppress {extraRequire} */
goog.require('ngeo.FeatureOverlayMgr');
/** @suppress {extraRequire} */
goog.require('ngeo.ScaleselectorOptions');
/** @suppress {extraRequire} */
goog.require('ngeo.scaleselectorDirective');
goog.require('ngeo.ToolActivate');
goog.require('ngeo.ToolActivateMgr');
goog.require('ol.Collection');
goog.require('ol.Map');
goog.require('ol.View');
goog.require('ol.control.ScaleLine');
goog.require('ol.control.Zoom');
goog.require('ol.interaction');
goog.require('ol.layer.Vector');
goog.require('ol.source.Vector');
goog.require('ol.style.Fill');
goog.require('ol.style.Stroke');
goog.require('ol.style.Style');
goog.require('ol.style.Text');

gmf.module.value('isDesktop', true);

/** @suppress {extraRequire} */
goog.require('ngeo.sortableDirective');
/** @suppress {extraRequire} */
goog.require('ngeo.SortableOptions');

gmf.module.value('ngeoQueryOptions', {
  'limit': 20
});

gmf.module.value('ngeoMeasurePrecision', 3);
gmf.module.value('ngeoMeasureDecimals', 0);

/**
 * Desktop application abstract controller.
 *
 * This file includes `goog.require`'s for desktop components/directives used
 * by the HTML page and the controller to provide the configuration.
 *
 * @param {gmfx.Config} config A part of the application config.
 * @param {angular.Scope} $scope Scope.
 * @param {angular.$injector} $injector Main injector.
 * @constructor
 * @extends {gmf.AbstractController}
 * @ngdoc controller
 * @ngInject
 * @export
 */
gmf.AbstractDesktopController = function(config, $scope, $injector) {

  const viewConfig = {
    projection: ol.proj.get(`EPSG:${config.srid || 21781}`)
  };
  ol.obj.assign(viewConfig, config.mapViewConfig || {});

  /**
   * @type {ol.Map}
   * @export
   */
  this.map = new ol.Map({
    layers: [],
    view: new ol.View(viewConfig),
    controls: config.mapControls || [
      new ol.control.ScaleLine({
        target: document.getElementById('scaleline')
      }),
      new ol.control.Zoom({
        zoomInTipLabel: '',
        zoomOutTipLabel: ''
      })
    ],
    interactions: config.mapInteractions || ol.interaction.defaults({
      pinchRotate: false,
      altShiftDragRotate: false
    }),
    loadTilesWhileAnimating: true,
    loadTilesWhileInteracting: true
  });

  /**
   * @type {boolean}
   * @export
   */
  this.loginActive = false;

  /**
   * @type {boolean}
   * @export
   */
  this.toolsActive = false;

  /**
   * @type {boolean}
   * @export
   */
  this.modalShareShown = false;

  /**
   * @type {boolean}
   * @export
   */
  this.filterSelectorActive = false;

  /**
   * @type {boolean}
   * @export
   */
  this.editFeatureActive = false;

  /**
   * @type {boolean}
   * @export
   */
  this.googleStreetViewActive = false;

  /**
   * @type {!ol.style.Style}
   * @export
   */
  this.googleStreetViewStyle = new ol.style.Style({
    text: new ol.style.Text({
      fill: new ol.style.Fill({color: '#279B61'}),
      font: 'normal 30px FontAwesome',
      offsetY: -15,
      stroke: new ol.style.Stroke({color: '#ffffff', width: 3}),
      text: '\uf041'
    })
  });

  const body = $('body');

  // initialize tooltips
  body.tooltip({
    container: 'body',
    trigger: 'hover',
    selector: '[data-toggle="tooltip"]'
  });

  // deactivate tooltips on touch device
  body.on('touchstart.detectTouch', () => {
    body.tooltip('destroy');
    body.off('touchstart.detectTouch');
  });

  /**
   * Collection of features for the draw interaction
   * @type {ol.Collection.<ol.Feature>}
   */
  const ngeoFeatures = $injector.get('ngeoFeatures');

  /**
   * @type {ngeo.FeatureOverlay}
   * @export
   */
  this.drawFeatureLayer = $injector.get('ngeoFeatureOverlayMgr')
    .getFeatureOverlay();
  this.drawFeatureLayer.setFeatures(ngeoFeatures);

  const ngeoFeatureHelper = $injector.get('ngeoFeatureHelper');

  /**
   * @type {ol.layer.Vector}
   * @export
   */
  this.editFeatureVectorLayer = new ol.layer.Vector({
    source: new ol.source.Vector({
      wrapX: false,
      features: new ol.Collection()
    }),
    style(feature, resolution) {
      return ngeoFeatureHelper.createEditingStyles(feature);
    }
    // style: ngeoFeatureHelper.createEditingStyles.bind(ngeoFeatureHelper)
  });
  this.editFeatureVectorLayer.setMap(this.map);

  /**
   * The ngeo ToolActivate manager service.
   * @type {ngeo.ToolActivateMgr}
   */
  const ngeoToolActivateMgr = $injector.get('ngeoToolActivateMgr');

  const editFeatureActivate = new ngeo.ToolActivate(this, 'editFeatureActive');
  ngeoToolActivateMgr.registerTool('mapTools', editFeatureActivate, false);

  const googleStreetViewActivate = new ngeo.ToolActivate(
    this,
    'googleStreetViewActive'
  );
  ngeoToolActivateMgr.registerTool('mapTools', googleStreetViewActivate, false);

  /**
   * @type {ngeo.ScaleselectorOptions}
   * @export
   */
  this.scaleSelectorOptions = {
    'dropup': true
  };

  /**
   * @type {ol.geom.LineString}
   * @export
   */
  this.profileLine = null;

  gmf.AbstractController.call(this, config, $scope, $injector);

  // close the login panel on successful login
  $scope.$watch(() => this.gmfUser.username, (newVal) => {
    if (newVal !== null && this.loginActive) {
      this.loginActive = false;
    }
  });

};
ol.inherits(gmf.AbstractDesktopController, gmf.AbstractController);

gmf.module.controller(
  'AbstractDesktopController',
  gmf.AbstractDesktopController);
<|endoftext|>


<commit_before>const electron = require('electron');
// Module to control application life.
const {app} = electron;
// Module to create native browser window.
const {BrowserWindow} = electron;

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win;

function createWindow() {
    // Create the browser window.
    win = new BrowserWindow({width: 800, height: 600});

    // and load the index.html of the app.
    win.loadURL(`file://${__dirname}/index.html`);

		// Emitted when the window is closed.
		win.on('closed', () => {
		    // Dereference the window object, usually you would store windows
		    // in an array if your app supports multi windows, this is the time
		    // when you should delete the corresponding element.
		    win = null;
		});
	       }

    // This method will be called when Electron has finished
    // initialization and is ready to create browser windows.
    // Some APIs can only be used after this event occurs.
    app.on('ready', createWindow);

    // Quit when all windows are closed.
    app.on('window-all-closed', () => {
	// On OS X it is common for applications and their menu bar
	// to stay active until the user quits explicitly with Cmd + Q
	if (process.platform !== 'darwin') {
	    app.quit();
	}
    });

    app.on('activate', () => {
	// On OS X it's common to re-create a window in the app when the
	// dock icon is clicked and there are no other windows open.
	if (win === null) {
	    createWindow();
	}
    });

    // In this file you can include the rest of your app's specific main process
    // code. You can also put them in separate files and require them here.
<commit_msg>res up<commit_after>const electron = require('electron');
// Module to control application life.
const {app} = electron;
// Module to create native browser window.
const {BrowserWindow} = electron;

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win;

function createWindow() {
    // Create the browser window.
    win = new BrowserWindow({width: 1200, height: 720});

    // and load the index.html of the app.
    win.loadURL(`file://${__dirname}/index.html`);

		// Emitted when the window is closed.
		win.on('closed', () => {
		    // Dereference the window object, usually you would store windows
		    // in an array if your app supports multi windows, this is the time
		    // when you should delete the corresponding element.
		    win = null;
		});
	       }

    // This method will be called when Electron has finished
    // initialization and is ready to create browser windows.
    // Some APIs can only be used after this event occurs.
    app.on('ready', createWindow);

    // Quit when all windows are closed.
    app.on('window-all-closed', () => {
	// On OS X it is common for applications and their menu bar
	// to stay active until the user quits explicitly with Cmd + Q
	if (process.platform !== 'darwin') {
	    app.quit();
	}
    });

    app.on('activate', () => {
	// On OS X it's common to re-create a window in the app when the
	// dock icon is clicked and there are no other windows open.
	if (win === null) {
	    createWindow();
	}
    });

    // In this file you can include the rest of your app's specific main process
    // code. You can also put them in separate files and require them here.
<|endoftext|>


<commit_before>export const INITIAL_WIDTH = 40
export const INITIAL_HEIGHT = 20

const setCellActionHandler = (state, action) => {
  const {x, y, live} = action.payload
  const cells = state.cells.slice()
  cells[x] = cells[x].slice()
  cells[x][y] = live
  const newState = { ...state, cells: cells }
  return newState
}

const randomizeActionHandler = (state, action) => {
  const newState = { ...state, cells: makeCells(state.width, state.height) }
  for (let x = 0; x < state.width; x++) {
    for (let y = 0; y < state.height; y++) {
      newState.cells[x][y] = Math.random() > 0.8
    }
  }
  return newState
}

const clearActionHandler = (state, action) => {
  return { ...state, cells: makeCells(state.width, state.height) }
}

const stepActionHandler = (state, action) => {
  const board = state
  const {width, height} = board
  const newCells = makeCells(width, height)
  for (let x = 0; x < width; x++) {
    for (let y = 0; y < width; y++) {
      newCells[x][y] = shouldLiveInNextGeneration(board, x, y)
    }
  }
  const newBoard = {...board, cells: newCells}
  return newBoard
}

export const makeCells = (width, height) => {
  const cells = []
  for (let x = 0; x < width; x++) {
    const row = []
    cells.push(row)
    for (let y = 0; y < height; y++) {
      row.push(false)
    }
  }

  return cells
}

const shouldLiveInNextGeneration = (board, x, y) => {
  const alive = board.cells[x][y]
  const neighbourCount = neighbours(board, x, y)
  return alive ? (neighbourCount >= 2 && neighbourCount <= 3) : (neighbourCount === 3)
}

export const neighbours = (board, x, y) => {
  return aliveCellsAt(board, x-1, y-1) +
     aliveCellsAt(board, x, y-1) +
     aliveCellsAt(board, x+1, y-1) +
     aliveCellsAt(board, x-1, y) +
     aliveCellsAt(board, x+1, y) +
     aliveCellsAt(board, x-1, y+1) +
     aliveCellsAt(board, x, y+1) +
     aliveCellsAt(board, x+1, y+1)
}

const aliveCellsAt = (board, x, y) => {
  if (x < 0 || x >= board.width) {
    return 0
  }
  if (y < 0 || y >= board.height) {
    return 0
  }
  return board.cells[x][y] ? 1 : 0
}

const resizeActionHandler = (state, action) => {
  const {width, height} = action.payload
  const cells = makeCells(width, height)
  const copyWidth = Math.min(width, state.width)
  const copyHeight = Math.min(height, state.height)
  for (let x = 0; x < copyWidth; x++) {
    for (let y = 0; y < copyHeight; y++) {
      cells[x][y] = state.cells[x][y]
    }
  }
  const newState = {...state, cells: cells, width: width, height: height}
  return newState
}

const initialState = () => {
  return {
    cells: makeCells(INITIAL_WIDTH, INITIAL_HEIGHT),
    width: INITIAL_WIDTH,
    height: INITIAL_HEIGHT
  }
}

const ACTION_HANDLERS = {
  SET_CELL: setCellActionHandler,
  RANDOMIZE: randomizeActionHandler,
  STEP: stepActionHandler,
  RESIZE: resizeActionHandler,
  CLEAR: clearActionHandler
}

// ------------------------------------
// Reducer
// ------------------------------------
export default function counterReducer (state, action) {
  if (state === undefined) {
    state = initialState()
  }

  const handler = ACTION_HANDLERS[action.type]
  return handler ? handler(state, action) : state
}
<commit_msg>Fix bug<commit_after>export const INITIAL_WIDTH = 40
export const INITIAL_HEIGHT = 20

const setCellActionHandler = (state, action) => {
  const {x, y, live} = action.payload
  const cells = state.cells.slice()
  cells[x] = cells[x].slice()
  cells[x][y] = live
  const newState = { ...state, cells: cells }
  return newState
}

const randomizeActionHandler = (state, action) => {
  const newState = { ...state, cells: makeCells(state.width, state.height) }
  for (let x = 0; x < state.width; x++) {
    for (let y = 0; y < state.height; y++) {
      newState.cells[x][y] = Math.random() > 0.8
    }
  }
  return newState
}

const clearActionHandler = (state, action) => {
  return { ...state, cells: makeCells(state.width, state.height) }
}

const stepActionHandler = (state, action) => {
  const board = state
  const {width, height} = board
  const newCells = makeCells(width, height)
  for (let x = 0; x < width; x++) {
    for (let y = 0; y < height; y++) {
      newCells[x][y] = shouldLiveInNextGeneration(board, x, y)
    }
  }
  const newBoard = {...board, cells: newCells}
  return newBoard
}

export const makeCells = (width, height) => {
  const cells = []
  for (let x = 0; x < width; x++) {
    const row = []
    cells.push(row)
    for (let y = 0; y < height; y++) {
      row.push(false)
    }
  }

  return cells
}

const shouldLiveInNextGeneration = (board, x, y) => {
  const alive = board.cells[x][y]
  const neighbourCount = neighbours(board, x, y)
  return alive ? (neighbourCount >= 2 && neighbourCount <= 3) : (neighbourCount === 3)
}

export const neighbours = (board, x, y) => {
  return aliveCellsAt(board, x-1, y-1) +
     aliveCellsAt(board, x, y-1) +
     aliveCellsAt(board, x+1, y-1) +
     aliveCellsAt(board, x-1, y) +
     aliveCellsAt(board, x+1, y) +
     aliveCellsAt(board, x-1, y+1) +
     aliveCellsAt(board, x, y+1) +
     aliveCellsAt(board, x+1, y+1)
}

const aliveCellsAt = (board, x, y) => {
  if (x < 0 || x >= board.width) {
    return 0
  }
  if (y < 0 || y >= board.height) {
    return 0
  }
  return board.cells[x][y] ? 1 : 0
}

const resizeActionHandler = (state, action) => {
  const {width, height} = action.payload
  const cells = makeCells(width, height)
  const copyWidth = Math.min(width, state.width)
  const copyHeight = Math.min(height, state.height)
  for (let x = 0; x < copyWidth; x++) {
    for (let y = 0; y < copyHeight; y++) {
      cells[x][y] = state.cells[x][y]
    }
  }
  const newState = {...state, cells: cells, width: width, height: height}
  return newState
}

const initialState = () => {
  return {
    cells: makeCells(INITIAL_WIDTH, INITIAL_HEIGHT),
    width: INITIAL_WIDTH,
    height: INITIAL_HEIGHT
  }
}

const ACTION_HANDLERS = {
  SET_CELL: setCellActionHandler,
  RANDOMIZE: randomizeActionHandler,
  STEP: stepActionHandler,
  RESIZE: resizeActionHandler,
  CLEAR: clearActionHandler
}

// ------------------------------------
// Reducer
// ------------------------------------
export default function counterReducer (state, action) {
  if (state === undefined) {
    state = initialState()
  }

  const handler = ACTION_HANDLERS[action.type]
  return handler ? handler(state, action) : state
}
<|endoftext|>


<commit_before>/* eslint-disable dot-notation */
/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2016
 */
import { pageInfoStrings, programStrings, tableStrings } from '../../localization';
import { MODAL_KEYS, formatDate } from '../../utilities';
import { ROUTES } from '../../navigation/constants';
import { PageActions } from './actions';

/**
 * PageInfo rows/columns for use with the PageInfo component.
 *
 *
 * To add a page, add the pages routeName (see: pages/index.js)
 * and a 2d array of page info rows to PER_PAGE_INFO_COLUMNS,
 * of the desired pageinfo rows needed on the page.
 *
 * To use in the new page: use the usePageReducer hook.
 * usePageReducer will inject a your pages reducer with a field
 * pageInfo - a function returned by getPageInfo. Passing
 * this function the particular pages base object - i.e,
 * transaction, requisition or stock and it's dispatch will return the
 * required pageInfo columns for the page.
 */

const PER_PAGE_INFO_COLUMNS = {
  [ROUTES.CUSTOMER_INVOICE]: [
    ['entryDate', 'confirmDate', 'enteredBy'],
    ['customer', 'theirRef', 'transactionComment'],
  ],
  [ROUTES.SUPPLIER_INVOICE]: [
    ['entryDate', 'confirmDate'],
    ['otherParty', 'theirRef', 'transactionComment'],
  ],
  [ROUTES.SUPPLIER_REQUISITION]: [
    ['entryDate', 'enteredBy'],
    ['otherParty', 'editableMonthsToSupply', 'requisitionComment'],
  ],
  [ROUTES.SUPPLIER_REQUISITION_WITH_PROGRAM]: [
    ['program', 'orderType', 'entryDate', 'enteredBy'],
    ['period', 'otherParty', 'monthsToSupply', 'requisitionComment'],
  ],
  [ROUTES.STOCKTAKE_EDITOR]: [['stocktakeName', 'stocktakeComment']],
  [ROUTES.STOCKTAKE_EDITOR_WITH_REASONS]: [['stocktakeName', 'stocktakeComment']],
  [ROUTES.CUSTOMER_REQUISITION]: [
    ['monthsToSupply', 'entryDate'],
    ['customer', 'requisitionComment'],
  ],
  [ROUTES.PRESCRIPTION]: [['entryDate', 'enteredBy'], ['customer', 'transactionComment']],
  stocktakeBatchEditModal: [['itemName']],
  stocktakeBatchEditModalWithReasons: [['itemName']],
};

const PAGE_INFO_ROWS = (pageObject, dispatch, route) => ({
  entryDate: {
    title: `${pageInfoStrings.entry_date}:`,
    info: formatDate(pageObject.entryDate) || 'N/A',
  },
  confirmDate: {
    title: `${pageInfoStrings.confirm_date}:`,
    info: formatDate(pageObject.confirmDate),
  },
  enteredBy: {
    title: `${pageInfoStrings.entered_by}:`,
    info: pageObject.enteredBy && pageObject.enteredBy.username,
  },
  customer: {
    title: `${pageInfoStrings.customer}:`,
    info: pageObject.otherPartyName,
  },
  theirRef: {
    title: `${pageInfoStrings.their_ref}:`,
    info: pageObject.theirRef,
    onPress: () => dispatch(PageActions.openModal(MODAL_KEYS.THEIR_REF_EDIT, route)),
    editableType: 'text',
  },
  transactionComment: {
    title: `${pageInfoStrings.comment}:`,
    info: pageObject.comment,
    onPress: () => dispatch(PageActions.openModal(MODAL_KEYS.TRANSACTION_COMMENT_EDIT, route)),
    editableType: 'text',
  },
  stocktakeComment: {
    title: `${pageInfoStrings.comment}:`,
    info: pageObject.comment,
    onPress: () => dispatch(PageActions.openModal(MODAL_KEYS.STOCKTAKE_COMMENT_EDIT, route)),
    editableType: 'text',
  },
  requisitionComment: {
    title: `${pageInfoStrings.comment}:`,
    info: pageObject.comment,
    onPress: () => dispatch(PageActions.openModal(MODAL_KEYS.REQUISITION_COMMENT_EDIT, route)),
    editableType: 'text',
  },
  otherParty: {
    title: `${pageInfoStrings.supplier}:`,
    info: pageObject.otherPartyName,
  },
  program: {
    title: `${programStrings.program}:`,
    info: pageObject.program && pageObject.program.name,
  },
  orderType: {
    title: `${programStrings.order_type}:`,
    info: pageObject.orderType,
  },
  editableMonthsToSupply: {
    title: `${pageInfoStrings.months_stock_required}:`,
    info: pageObject.monthsToSupply,
    onPress: () => dispatch(PageActions.openModal(MODAL_KEYS.SELECT_MONTH, route)),
    editableType: 'selectable',
  },
  period: {
    title: `${programStrings.period}:`,
    info: pageObject.period && pageObject.period.toInfoString(),
  },
  monthsToSupply: {
    title: `${pageInfoStrings.months_stock_required}:`,
    info: pageObject.monthsToSupply,
  },
  stocktakeName: {
    title: `${pageInfoStrings.stocktake_name}:`,
    info: pageObject.name,
    onPress: () => dispatch(PageActions.openModal(MODAL_KEYS.STOCKTAKE_NAME_EDIT, route)),
    editableType: 'text',
  },
  itemName: {
    title: `${tableStrings.item_name}`,
    info: pageObject.itemName,
    onPress: null,
  },
});

const getPageInfoColumns = page => {
  const pageInfoColumns = PER_PAGE_INFO_COLUMNS[page];

  if (!pageInfoColumns) return null;
  return (pageObjectParameter, dispatch, route) => {
    const pageInfoRows = PAGE_INFO_ROWS(pageObjectParameter, dispatch, route);
    return pageInfoColumns.map(pageInfoColumn =>
      pageInfoColumn.map(pageInfoKey => pageInfoRows[pageInfoKey])
    );
  };
};

export default getPageInfoColumns;
<commit_msg>Add prescriber page info<commit_after>/* eslint-disable dot-notation */
/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2016
 */
import { pageInfoStrings, programStrings, tableStrings } from '../../localization';
import { MODAL_KEYS, formatDate } from '../../utilities';
import { ROUTES } from '../../navigation/constants';
import { PageActions } from './actions';

/**
 * PageInfo rows/columns for use with the PageInfo component.
 *
 *
 * To add a page, add the pages routeName (see: pages/index.js)
 * and a 2d array of page info rows to PER_PAGE_INFO_COLUMNS,
 * of the desired pageinfo rows needed on the page.
 *
 * To use in the new page: use the usePageReducer hook.
 * usePageReducer will inject a your pages reducer with a field
 * pageInfo - a function returned by getPageInfo. Passing
 * this function the particular pages base object - i.e,
 * transaction, requisition or stock and it's dispatch will return the
 * required pageInfo columns for the page.
 */

const PER_PAGE_INFO_COLUMNS = {
  [ROUTES.CUSTOMER_INVOICE]: [
    ['entryDate', 'confirmDate', 'enteredBy'],
    ['customer', 'theirRef', 'transactionComment'],
  ],
  [ROUTES.SUPPLIER_INVOICE]: [
    ['entryDate', 'confirmDate'],
    ['otherParty', 'theirRef', 'transactionComment'],
  ],
  [ROUTES.SUPPLIER_REQUISITION]: [
    ['entryDate', 'enteredBy'],
    ['otherParty', 'editableMonthsToSupply', 'requisitionComment'],
  ],
  [ROUTES.SUPPLIER_REQUISITION_WITH_PROGRAM]: [
    ['program', 'orderType', 'entryDate', 'enteredBy'],
    ['period', 'otherParty', 'monthsToSupply', 'requisitionComment'],
  ],
  [ROUTES.STOCKTAKE_EDITOR]: [['stocktakeName', 'stocktakeComment']],
  [ROUTES.STOCKTAKE_EDITOR_WITH_REASONS]: [['stocktakeName', 'stocktakeComment']],
  [ROUTES.CUSTOMER_REQUISITION]: [
    ['monthsToSupply', 'entryDate'],
    ['customer', 'requisitionComment'],
  ],
  [ROUTES.PRESCRIPTION]: [
    ['entryDate', 'enteredBy'],
    ['customer', 'transactionComment', 'prescriber'],
  ],
  stocktakeBatchEditModal: [['itemName']],
  stocktakeBatchEditModalWithReasons: [['itemName']],
};

const PAGE_INFO_ROWS = (pageObject, dispatch, route) => ({
  entryDate: {
    title: `${pageInfoStrings.entry_date}:`,
    info: formatDate(pageObject.entryDate) || 'N/A',
  },
  confirmDate: {
    title: `${pageInfoStrings.confirm_date}:`,
    info: formatDate(pageObject.confirmDate),
  },
  enteredBy: {
    title: `${pageInfoStrings.entered_by}:`,
    info: pageObject.enteredBy && pageObject.enteredBy.username,
  },
  customer: {
    title: `${pageInfoStrings.customer}:`,
    info: pageObject.otherPartyName,
  },
  theirRef: {
    title: `${pageInfoStrings.their_ref}:`,
    info: pageObject.theirRef,
    onPress: () => dispatch(PageActions.openModal(MODAL_KEYS.THEIR_REF_EDIT, route)),
    editableType: 'text',
  },
  transactionComment: {
    title: `${pageInfoStrings.comment}:`,
    info: pageObject.comment,
    onPress: () => dispatch(PageActions.openModal(MODAL_KEYS.TRANSACTION_COMMENT_EDIT, route)),
    editableType: 'text',
  },
  stocktakeComment: {
    title: `${pageInfoStrings.comment}:`,
    info: pageObject.comment,
    onPress: () => dispatch(PageActions.openModal(MODAL_KEYS.STOCKTAKE_COMMENT_EDIT, route)),
    editableType: 'text',
  },
  requisitionComment: {
    title: `${pageInfoStrings.comment}:`,
    info: pageObject.comment,
    onPress: () => dispatch(PageActions.openModal(MODAL_KEYS.REQUISITION_COMMENT_EDIT, route)),
    editableType: 'text',
  },
  otherParty: {
    title: `${pageInfoStrings.supplier}:`,
    info: pageObject.otherPartyName,
  },
  program: {
    title: `${programStrings.program}:`,
    info: pageObject.program && pageObject.program.name,
  },
  orderType: {
    title: `${programStrings.order_type}:`,
    info: pageObject.orderType,
  },
  editableMonthsToSupply: {
    title: `${pageInfoStrings.months_stock_required}:`,
    info: pageObject.monthsToSupply,
    onPress: () => dispatch(PageActions.openModal(MODAL_KEYS.SELECT_MONTH, route)),
    editableType: 'selectable',
  },
  period: {
    title: `${programStrings.period}:`,
    info: pageObject.period && pageObject.period.toInfoString(),
  },
  monthsToSupply: {
    title: `${pageInfoStrings.months_stock_required}:`,
    info: pageObject.monthsToSupply,
  },
  stocktakeName: {
    title: `${pageInfoStrings.stocktake_name}:`,
    info: pageObject.name,
    onPress: () => dispatch(PageActions.openModal(MODAL_KEYS.STOCKTAKE_NAME_EDIT, route)),
    editableType: 'text',
  },
  itemName: {
    title: `${tableStrings.item_name}`,
    info: pageObject.itemName,
    onPress: null,
  },
  prescriber: {
    title: 'Prescriber',
    info: pageObject?.prescriber?.firstName,
    onPress: () => dispatch(PageActions.openModal(MODAL_KEYS.SELECT_PRESCRIBER, route)),
  },
});

const getPageInfoColumns = page => {
  const pageInfoColumns = PER_PAGE_INFO_COLUMNS[page];

  if (!pageInfoColumns) return null;
  return (pageObjectParameter, dispatch, route) => {
    const pageInfoRows = PAGE_INFO_ROWS(pageObjectParameter, dispatch, route);
    return pageInfoColumns.map(pageInfoColumn =>
      pageInfoColumn.map(pageInfoKey => pageInfoRows[pageInfoKey])
    );
  };
};

export default getPageInfoColumns;
<|endoftext|>