<commit_before>
import moment from 'moment';

import Billing from "../models/billing";
import BillingPolicy from "../models/billingPolicy";
import Wallet from "../models/wallet";
import WalletPayment from "../models/walletPayment";

import Client from "../models/client";
import Business from "../models/business";
import Insurance from "../models/insurance";

import JSZip from 'jszip';
import Docxtemplater from 'docxtemplater';
import excelbuilder from 'msexcel-builder';
import fs from 'fs';
import path from 'path';

const pathRender = `download`;
const pathDownload = `./public/${pathRender}`;

if (!fs.existsSync(pathDownload)){
    fs.mkdirSync(pathDownload);
}

let billingController = function (app, control={auth, passport, acl}){

   function controller (req, res, next) {
      req.controller = "billing";
      return next();
   }

   function findAction (callback){
      Billing.find({}, function (err, docs) {
         if (!err) {
            callback(docs);
         }
      });
   }

   app.get('/billing/filter',[control.auth, controller], (req, res) => {
      let $filter =  global.filter(req.query.filter);
      Billing.find($filter, function (err, docs) {
         if (typeof docs !== 'undefined') {
            control.log(req.route.path, req.user);

            res.send({msg: "OK", billings: docs});

         } else {
            let error=global.error(err, 0, req.controller);
            res.send({msg: 'ERROR', err: error});
         }
      });

   });

   app.get('/billing/list', [control.auth, controller, control.acl], (req, res) => {

      let typeList = app.locals.typeList;
      let filter = {};
      if(typeList=="99097f2c1f"){
         filter = {"userCreate": req.user.idUser};
      } else if(typeList=="99097f2c1c"){
         filter = {"branchCreate": req.user.idBranch};
      } else {
         filter = {};
      }

      Billing.find(filter, function (err, docs) {
         if (typeof docs !== 'undefined') {
            control.log(req.route.path, req.user);

            res.send({msg: "OK", billings: docs});

         } else {
            let error=global.error(err, 0, req.controller);
            res.send({msg: 'ERROR', err: error});
         }
      });

   });

   app.get('/billing/view/:id', [control.auth, controller, control.acl], (req, res) => {

      Billing.findById(req.params.id, function (err, doc) {
         if (!err) {
            control.log(req.route.path, req.user);
            res.send({msg: "OK", billing: doc});
         } else {
            let error=global.error(err, 0, req.controller);
            res.send({msg: 'ERROR', err: error});
         }
      });

   });

   app.post('/billing/add', [control.auth, controller, control.acl], (req, res) => {
      let $data = req.body.billing;
      let $billinData = $data;
      let $billingPolicy = $data.items;
      let $moment = moment();
      delete($billinData.items);
      $billinData["dateCreate"] = $moment;
      $billinData["userCreate"] = req.user.idUser;
      $billinData["branchCreate"] = req.user.idBranch;
      $billinData["dateUpdate"] = $moment;
      $billinData["userUpdate"] = req.user.idUser;

      let ClientBilling;
      if($data.typeBilling=='99097f2c1f'){
         ClientBilling = Client;
      }
      else if($data.typeBilling=='99097f2c1c'){
         ClientBilling = Business;
      }
      else if($data.typeBilling=='99097f2c1d'){
         ClientBilling = Insurance;
      }
      ClientBilling.findById($data.idDetailsClientBilling, function (err, doc) {
         if (!err) {
            //control.log(req.route.path, req.user);
            //res.send({msg: "OK", billing: doc});
            $billinData["detailsClientBilling"] = doc;
            let billing = new Billing($billinData);
            billing.save((err, doc) => {
               if(!err){
                  control.log(req.route.path, req.user);
                  $billingPolicy.forEach(function (item, index) {
                     $billingPolicy[index]["idBilling"]=doc._id;
                     $billingPolicy[index]["billing"]=doc._id;
                     $billingPolicy[index]["dateCreate"] = $moment;
                     $billingPolicy[index]["userCreate"] = req.user.idUser;
                     $billingPolicy[index]["dateUpdate"] = $moment;
                     $billingPolicy[index]["userUpdate"] = req.user.idUser;
                  })
                  BillingPolicy.insertMany($billingPolicy, (err, docs) => {
                     if(!err){
                        let wallet = new Wallet({
                           idBilling: doc._id,
                           DetailsBillingData: doc,
                           expirationDate: $billinData.firstPaymentDate,
                           paymentValue: $billinData.valueEqualPayments,
                           detailsWallet: "",
                           dateCreate: $moment,
                           userCreate: req.user.idUser,
                           dateUpdate: $moment,
                           userUpdate: req.user.idUser
                        });
                        wallet.save((err, docWallet) => {
                           let $walletPayment =[];
                           let $expirationDate = $billinData.firstPaymentDate;
                           let $paymentValue = $billinData.valueEqualPayments;
                           for(let i = 0; i < $billinData.equalPayments; i++){
                              let obj= {
                                  idWallet:docWallet._id,
                                  wallet:docWallet._id,
                                  expirationDate:$expirationDate,
                                  paymentValue: $paymentValue,
                                  arrayWalletPayment: [],
                                  dateCreate:$moment,
                                  userCreate: req.user.idUser,
                                  dateUpdate:$moment,
                                  userUpdate:req.user.idUser
                              }
                              $walletPayment.push(obj);
                              $expirationDate = moment($expirationDate).add(1, 'month');
                           }
                           WalletPayment.insertMany($walletPayment, (err, docsWalletPayment) => { });
                        });
                        findAction(function(docs){
                           res.send({msg: "OK", update: docs});
                        });
                     } else {
                        let error=global.error(err, 0, req.controller);
                        res.send({msg: 'ERROR', err: error});
                     }
                  });
               } else {
                  let error=global.error(err, 0, req.controller);
                  res.send({msg: 'ERROR', err: error});
               }
            });
         } else {
            let error=global.error(err, 0, req.controller);
            res.send({msg: 'ERROR', err: error});
         }
      });

   });

   app.post('/billing/edit/:id', [control.auth, controller, control.acl], (req, res) => {

      let filter = {
         _id: req.params.id
      }

      let $data = req.body.billing;
      let $billinData = $data;
      let $billingPolicy = $data.items;
      let $moment = moment();
      delete($billinData.items);
      $billinData["dateUpdate"] = $moment;
      $billinData["userUpdate"] = req.user.idUser;
      let billing = new Billing($billinData);
      let update = $billinData;

      Billing.findOneAndUpdate(filter, update, function (err1, doc) {
         if (!err1) {
            //res.send({msg: "OK", update: docs});
            filter = {
               idBilling: req.params.id
            }
            BillingPolicy.remove(filter, function(err2, response) {

               if (!err2) {
                  $billingPolicy.forEach(function (item, index) {
                     $billingPolicy[index]["idBilling"]=doc._id;
                     $billingPolicy[index]["billing"]=doc._id;
                     $billingPolicy[index]["dateCreate"] = $moment;
                     $billingPolicy[index]["userCreate"] = req.user.idUser;
                     $billingPolicy[index]["dateUpdate"] = $moment;
                     $billingPolicy[index]["userUpdate"] = req.user.idUser;
                  })
                  BillingPolicy.insertMany($billingPolicy, (err3, docs) => {
                     if(!err3){
                        findAction(function(docs){
                           res.send({msg: "OK", update: docs});
                        });
                     } else {
                        let error=global.error(err3, 0, req.controller);
                        res.send({msg: 'ERROR', err: error});
                     }
                  });

               } else {
                  let error=global.error(err2, 0, req.controller);
                  res.send({msg: 'ERROR', err: error});
               }
            });

         } else {
            let error=global.error(err1, 0, req.controller);
            res.send({msg: 'ERROR', err: error});
         }
      });

   });

   app.delete('/billing/delete/:id', [control.auth, controller, control.acl], (req, res) => {

      let filter = {
         _id: req.params.id
      }

      Billing.findByIdAndRemove(filter, function (err, doc) {
         if(!err){
            findAction(function(docs){
               control.log(req.route.path, req.user);
               res.send({msg: "OK", update: docs});
            });
         } else {
            let error=global.error(err, 0, req.controller);
            res.send({msg: 'ERROR', err: error});
         }
      });

   });

   app.post('/billing/report', [control.auth, controller, control.acl], (req, res) => {

      let $filter =  global.filter(req.body.filter);
      Billing.find($filter, function (err, docs) {
         if (typeof docs !== 'undefined') {

         /*Ramo.populate(docs, {path: "ramo"},function(err, docs){
         City.populate(docs, {path: "city"},function(err, docs){
         Branch.populate(docs, {path: "branchCreate"},function(err, docs){
         PolicyType.populate(docs, {path: "policyType"},function(err, docs){*/

            var file = 'billing.xlsx';
            var outPutFile = moment().format('YYYY-MM-DD-h:mm:ss') + file;
            var pathDownload = __dirname+'/../../public/download/';
            var workbook = excelbuilder.createWorkbook(pathDownload, outPutFile)
            var sheet1 = workbook.createSheet('sheet1', 10, 12);

            var cols = [2,3,4,5,6,7,8,9];
            var rowIni = 2;
            sheet1.set(cols[0], rowIni, 'Agencia');
            sheet1.set(cols[1], rowIni, 'Ciudad');
            sheet1.set(cols[2], rowIni, 'Nombre Cliente');
            sheet1.set(cols[3], rowIni, 'Numero de Factura');
            sheet1.set(cols[4], rowIni, 'Nombre Ramo');
            sheet1.set(cols[5], rowIni, 'Fecha de Inicio de Vigencia');
            sheet1.set(cols[6], rowIni, 'Fecha de fin de Vigencia');
            sheet1.set(cols[7], rowIni, 'Fecha de Factura');

            console.log(docs);
            let $length = docs.length;
            for (var i = 0; i < $length; i++) {
               rowIni++;
               let $cliente = '';
                  if(docs[i].typeRecipient == 'CLIENTE'){
                     $cliente = docs[i].recipient.name+' '+docs[i].recipient.lastName
                  }
               sheet1.set(cols[0], rowIni, docs[i]);
               /*sheet1.set(cols[0], rowIni, docs[i].branchCreate.name);
               sheet1.set(cols[1], rowIni, docs[i].city.name);
               sheet1.set(cols[2], rowIni, $cliente);
               sheet1.set(cols[3], rowIni, docs[i].policyNumber);
               sheet1.set(cols[4], rowIni, docs[i].ramo.name);
               sheet1.set(cols[5], rowIni, docs[i].policyType.name);
               sheet1.set(cols[6], rowIni, docs[i].startDate);
               sheet1.set(cols[7], rowIni, docs[i].finishDate);*/
            }

            workbook.save(function(err1, resp1){
               if (!err1){
                  console.log('congratulations, your workbook created');
                  res.send({msg: "OK", doc_name: outPutFile});
               }
               else{
                  workbook.cancel();
                  res.send({msg: "ERROR", err: err1});
               }
            });

         /*});
         });
         });
         });*/

         } else {
            let error=global.error(err, 0, req.controller);
            res.send({msg: 'ERROR', err: error});
         }
      });

   });

}

export default billingController
<commit_msg>fixed save several walletpayments<commit_after>
import moment from 'moment';

import Billing from "../models/billing";
import BillingPolicy from "../models/billingPolicy";
import Wallet from "../models/wallet";
import WalletPayment from "../models/walletPayment";

import Client from "../models/client";
import Business from "../models/business";
import Insurance from "../models/insurance";

import JSZip from 'jszip';
import Docxtemplater from 'docxtemplater';
import excelbuilder from 'msexcel-builder';
import fs from 'fs';
import path from 'path';

const pathRender = `download`;
const pathDownload = `./public/${pathRender}`;

if (!fs.existsSync(pathDownload)){
    fs.mkdirSync(pathDownload);
}

let billingController = function (app, control={auth, passport, acl}){

   function controller (req, res, next) {
      req.controller = "billing";
      return next();
   }

   function findAction (callback){
      Billing.find({}, function (err, docs) {
         if (!err) {
            callback(docs);
         }
      });
   }

   app.get('/billing/filter',[control.auth, controller], (req, res) => {
      let $filter =  global.filter(req.query.filter);
      Billing.find($filter, function (err, docs) {
         if (typeof docs !== 'undefined') {
            control.log(req.route.path, req.user);

            res.send({msg: "OK", billings: docs});

         } else {
            let error=global.error(err, 0, req.controller);
            res.send({msg: 'ERROR', err: error});
         }
      });

   });

   app.get('/billing/list', [control.auth, controller, control.acl], (req, res) => {

      let typeList = app.locals.typeList;
      let filter = {};
      if(typeList=="99097f2c1f"){
         filter = {"userCreate": req.user.idUser};
      } else if(typeList=="99097f2c1c"){
         filter = {"branchCreate": req.user.idBranch};
      } else {
         filter = {};
      }

      Billing.find(filter, function (err, docs) {
         if (typeof docs !== 'undefined') {
            control.log(req.route.path, req.user);

            res.send({msg: "OK", billings: docs});

         } else {
            let error=global.error(err, 0, req.controller);
            res.send({msg: 'ERROR', err: error});
         }
      });

   });

   app.get('/billing/view/:id', [control.auth, controller, control.acl], (req, res) => {

      Billing.findById(req.params.id, function (err, doc) {
         if (!err) {
            control.log(req.route.path, req.user);
            res.send({msg: "OK", billing: doc});
         } else {
            let error=global.error(err, 0, req.controller);
            res.send({msg: 'ERROR', err: error});
         }
      });

   });

   app.post('/billing/add', [control.auth, controller, control.acl], (req, res) => {
      let $data = req.body.billing;
      let $billinData = $data;
      let $billingPolicy = $data.items;
      let $moment = moment();
      delete($billinData.items);
      $billinData["dateCreate"] = $moment;
      $billinData["userCreate"] = req.user.idUser;
      $billinData["branchCreate"] = req.user.idBranch;
      $billinData["dateUpdate"] = $moment;
      $billinData["userUpdate"] = req.user.idUser;

      let ClientBilling;
      if($data.typeBilling=='99097f2c1f'){
         ClientBilling = Client;
      }
      else if($data.typeBilling=='99097f2c1c'){
         ClientBilling = Business;
      }
      else if($data.typeBilling=='99097f2c1d'){
         ClientBilling = Insurance;
      }
      ClientBilling.findById($data.idDetailsClientBilling, function (err, doc) {
         if (!err) {
            //control.log(req.route.path, req.user);
            //res.send({msg: "OK", billing: doc});
            $billinData["detailsClientBilling"] = doc;
            let billing = new Billing($billinData);
            billing.save((err, doc) => {
               if(!err){
                  control.log(req.route.path, req.user);
                  $billingPolicy.forEach(function (item, index) {
                     $billingPolicy[index]["idBilling"]=doc._id;
                     $billingPolicy[index]["billing"]=doc._id;
                     $billingPolicy[index]["dateCreate"] = $moment;
                     $billingPolicy[index]["userCreate"] = req.user.idUser;
                     $billingPolicy[index]["dateUpdate"] = $moment;
                     $billingPolicy[index]["userUpdate"] = req.user.idUser;
                  })
                  BillingPolicy.insertMany($billingPolicy, (err, docs) => {
                     if(!err){
                        let wallet = new Wallet({
                           idBilling: doc._id,
                           DetailsBillingData: doc,
                           expirationDate: $billinData.firstPaymentDate,
                           paymentValue: $billinData.valueEqualPayments,
                           detailsWallet: "",
                           dateCreate: $moment,
                           userCreate: req.user.idUser,
                           dateUpdate: $moment,
                           userUpdate: req.user.idUser
                        });
                        wallet.save((err, docWallet) => {
                           let $walletPayment =[];
                           let $expirationDate = $billinData.firstPaymentDate;
                           let $paymentValue = $billinData.valueEqualPayments;
                           let $total = parseInt($billinData.equalPayments);
                           for(let i = 0; i < $total; i++){
                              let obj= {
                                  idWallet:docWallet._id,
                                  wallet:docWallet._id,
                                  expirationDate:$expirationDate,
                                  paymentValue: $paymentValue,
                                  arrayWalletPayment: [],
                                  dateCreate:$moment,
                                  userCreate: req.user.idUser,
                                  dateUpdate:$moment,
                                  userUpdate:req.user.idUser
                              }
                              $walletPayment[i] = obj;

                              $expirationDate = moment($expirationDate).add(1, 'month').format('YYYY-MM-DD');

                              let walletPayment = new WalletPayment(obj);
                              walletPayment.save((err, docWalletPayment) => {
                              });

                           }
                           //WalletPayment.insertMany($walletPayment, (err, docsWalletPayment) => { });
                        });
                        findAction(function(docs){
                           res.send({msg: "OK", update: docs});
                        });
                     } else {
                        let error=global.error(err, 0, req.controller);
                        res.send({msg: 'ERROR', err: error});
                     }
                  });
               } else {
                  let error=global.error(err, 0, req.controller);
                  res.send({msg: 'ERROR', err: error});
               }
            });
         } else {
            let error=global.error(err, 0, req.controller);
            res.send({msg: 'ERROR', err: error});
         }
      });

   });

   app.post('/billing/edit/:id', [control.auth, controller, control.acl], (req, res) => {

      let filter = {
         _id: req.params.id
      }

      let $data = req.body.billing;
      let $billinData = $data;
      let $billingPolicy = $data.items;
      let $moment = moment();
      delete($billinData.items);
      $billinData["dateUpdate"] = $moment;
      $billinData["userUpdate"] = req.user.idUser;
      let billing = new Billing($billinData);
      let update = $billinData;

      Billing.findOneAndUpdate(filter, update, function (err1, doc) {
         if (!err1) {
            //res.send({msg: "OK", update: docs});
            filter = {
               idBilling: req.params.id
            }
            BillingPolicy.remove(filter, function(err2, response) {

               if (!err2) {
                  $billingPolicy.forEach(function (item, index) {
                     $billingPolicy[index]["idBilling"]=doc._id;
                     $billingPolicy[index]["billing"]=doc._id;
                     $billingPolicy[index]["dateCreate"] = $moment;
                     $billingPolicy[index]["userCreate"] = req.user.idUser;
                     $billingPolicy[index]["dateUpdate"] = $moment;
                     $billingPolicy[index]["userUpdate"] = req.user.idUser;
                  })
                  BillingPolicy.insertMany($billingPolicy, (err3, docs) => {
                     if(!err3){
                        findAction(function(docs){
                           res.send({msg: "OK", update: docs});
                        });
                     } else {
                        let error=global.error(err3, 0, req.controller);
                        res.send({msg: 'ERROR', err: error});
                     }
                  });

               } else {
                  let error=global.error(err2, 0, req.controller);
                  res.send({msg: 'ERROR', err: error});
               }
            });

         } else {
            let error=global.error(err1, 0, req.controller);
            res.send({msg: 'ERROR', err: error});
         }
      });

   });

   app.delete('/billing/delete/:id', [control.auth, controller, control.acl], (req, res) => {

      let filter = {
         _id: req.params.id
      }

      Billing.findByIdAndRemove(filter, function (err, doc) {
         if(!err){
            findAction(function(docs){
               control.log(req.route.path, req.user);
               res.send({msg: "OK", update: docs});
            });
         } else {
            let error=global.error(err, 0, req.controller);
            res.send({msg: 'ERROR', err: error});
         }
      });

   });

   app.post('/billing/report', [control.auth, controller, control.acl], (req, res) => {

      let $filter =  global.filter(req.body.filter);
      Billing.find($filter, function (err, docs) {
         if (typeof docs !== 'undefined') {

         /*Ramo.populate(docs, {path: "ramo"},function(err, docs){
         City.populate(docs, {path: "city"},function(err, docs){
         Branch.populate(docs, {path: "branchCreate"},function(err, docs){
         PolicyType.populate(docs, {path: "policyType"},function(err, docs){*/

            var file = 'billing.xlsx';
            var outPutFile = moment().format('YYYY-MM-DD-h:mm:ss') + file;
            var pathDownload = __dirname+'/../../public/download/';
            var workbook = excelbuilder.createWorkbook(pathDownload, outPutFile)
            var sheet1 = workbook.createSheet('sheet1', 10, 12);

            var cols = [2,3,4,5,6,7,8,9];
            var rowIni = 2;
            sheet1.set(cols[0], rowIni, 'Agencia');
            sheet1.set(cols[1], rowIni, 'Ciudad');
            sheet1.set(cols[2], rowIni, 'Nombre Cliente');
            sheet1.set(cols[3], rowIni, 'Numero de Factura');
            sheet1.set(cols[4], rowIni, 'Nombre Ramo');
            sheet1.set(cols[5], rowIni, 'Fecha de Inicio de Vigencia');
            sheet1.set(cols[6], rowIni, 'Fecha de fin de Vigencia');
            sheet1.set(cols[7], rowIni, 'Fecha de Factura');

            console.log(docs);
            let $length = docs.length;
            for (var i = 0; i < $length; i++) {
               rowIni++;
               let $cliente = '';
                  if(docs[i].typeRecipient == 'CLIENTE'){
                     $cliente = docs[i].recipient.name+' '+docs[i].recipient.lastName
                  }
               sheet1.set(cols[0], rowIni, docs[i]);
               /*sheet1.set(cols[0], rowIni, docs[i].branchCreate.name);
               sheet1.set(cols[1], rowIni, docs[i].city.name);
               sheet1.set(cols[2], rowIni, $cliente);
               sheet1.set(cols[3], rowIni, docs[i].policyNumber);
               sheet1.set(cols[4], rowIni, docs[i].ramo.name);
               sheet1.set(cols[5], rowIni, docs[i].policyType.name);
               sheet1.set(cols[6], rowIni, docs[i].startDate);
               sheet1.set(cols[7], rowIni, docs[i].finishDate);*/
            }

            workbook.save(function(err1, resp1){
               if (!err1){
                  console.log('congratulations, your workbook created');
                  res.send({msg: "OK", doc_name: outPutFile});
               }
               else{
                  workbook.cancel();
                  res.send({msg: "ERROR", err: err1});
               }
            });

         /*});
         });
         });
         });*/

         } else {
            let error=global.error(err, 0, req.controller);
            res.send({msg: 'ERROR', err: error});
         }
      });

   });

}

export default billingController
<|endoftext|>


<commit_before>//This classes responsiblities:

//Class 1:
//Creating the div for cards to be added to so they are on seperate pages

//Class 2:
//Converting JSON data to card data

var jira = {};

jira.App = function (element, baseUrl, fixVersion, color, qrcode, parentEnabled, componentEnabled, tagEnabled, businessValue) {
	if (baseUrl == "") {
		alert("You need to set a valid Jira Location")
		return;
	}
	this.baseUrl = baseUrl;
	this.element = element;
	this.colorEnabled = color;
	this.qrcodeEnabled = qrcode;
	this.parentDescriptionEnabled = parentEnabled;
	this.componentEnabled = componentEnabled;
	this.tagEnabled = tagEnabled;
	this.businessValue = businessValue;
	this.cardsAdded = 0;
	this.currentPage = null;
    this.issueRequester = new JiraApiHandler(this.baseUrl, this);
};

jira.App.prototype.requestIssues = function(selectedIssueIds) {
	this.selectedIssueIds = selectedIssueIds;
	this.issueRequester.requestIssues(selectedIssueIds, function(issues, issueMap) {
        this.onIssuesAvailable(issues, issueMap);
    }.bind(this));
};

jira.App.prototype.onIssuesAvailable = function(issueIds, issueMap) {
	for (var i = 0; i < issueIds.length; i++) {
		var cardModel = issueMap[issueIds[i]];

		var cardView = new CardView(
			cardModel,
			issueMap,
			["Doc", "Demo", "Review"],
			this.parentDescriptionEnabled,
			this.componentEnabled,
			this.tagEnabled,
			this.colorEnabled,
			this.qrcodeEnabled,
			this.businessValue,
            true
		);

		this.addTicket(cardView);
	}
};

jira.App.prototype.addTicket = function(card) {
	var pageElement = this.getPageForNewCard();
	pageElement.appendChild(card.getElement());
};

jira.App.prototype.getPageForNewCard = function() {
	if (this.currentPage == null || this.cardsAdded % 6 === 0) {
		this.currentPage = document.createElement("div");
		this.currentPage.className = "page";
		this.element.appendChild(this.currentPage);
	}
	this.cardsAdded++;
	return this.currentPage;
};<commit_msg>Subtasks now show Epic as well<commit_after>//This classes responsiblities:

//Class 1:
//Creating the div for cards to be added to so they are on seperate pages

//Class 2:
//Converting JSON data to card data

var jira = {};

jira.App = function (element, baseUrl, fixVersion, color, qrcode, parentEnabled, componentEnabled, tagEnabled, businessValue) {
	if (baseUrl == "") {
		alert("You need to set a valid Jira Location")
		return;
	}
	this.baseUrl = baseUrl;
	this.element = element;
	this.colorEnabled = color;
	this.qrcodeEnabled = qrcode;
	this.parentDescriptionEnabled = parentEnabled;
	this.componentEnabled = componentEnabled;
	this.tagEnabled = tagEnabled;
	this.businessValue = businessValue;
	this.cardsAdded = 0;
	this.currentPage = null;
    this.issueRequester = new JiraApiHandler(this.baseUrl, this);
};

jira.App.prototype.requestIssues = function(selectedIssueIds) {
	this.selectedIssueIds = selectedIssueIds;
	this.issueRequester.requestIssues(selectedIssueIds, function(issues, issueMap) {
        this.onIssuesAvailable(issues, issueMap);
    }.bind(this));
};

jira.App.prototype.onIssuesAvailable = function(issueIds, issueMap) {

	for (var i = 0; i < issueIds.length; i++) {
		var cardModel = issueMap[issueIds[i]];

		//TODO: May god have mercy on my soul
		if (cardModel.parentIssueId !== null) {
			if (issueMap[cardModel.parentIssueId].epic !== null) {
				cardModel.epic = issueMap[cardModel.parentIssueId].epic;
			}
		}

		var cardView = new CardView(
			cardModel,
			issueMap,
			["Doc", "Demo", "Review"],
			this.parentDescriptionEnabled,
			this.componentEnabled,
			this.tagEnabled,
			this.colorEnabled,
			this.qrcodeEnabled,
			this.businessValue,
            true
		);

		this.addTicket(cardView);
	}
};

jira.App.prototype.addTicket = function(card) {
	var pageElement = this.getPageForNewCard();
	pageElement.appendChild(card.getElement());
};

jira.App.prototype.getPageForNewCard = function() {
	if (this.currentPage == null || this.cardsAdded % 6 === 0) {
		this.currentPage = document.createElement("div");
		this.currentPage.className = "page";
		this.element.appendChild(this.currentPage);
	}
	this.cardsAdded++;
	return this.currentPage;
};<|endoftext|>


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

// Components
import Button from "./components/button";

// Functions
import Addition from "./functions/addition";
import Subtract from "./functions/subtract";
import Multiply from "./functions/multiply";
import Divide from "./functions/divide";

import './App.css';
import './Color.css';

class App extends Component {

  constructor(props) {
    super(props);

    this.state = {
      input: "",
      math: null,
      sum: null,
      resetNext: false,
      firstEntry: true,
      theme: "red",
    };

    this.buttons = ["C", "(-)", "<", "/", 1, 2, 3, "*", 4, 5, 6, "-", 7 ,8, 9, "+", 0, ".", "="];
  }

  // Run when app is loaded
  componentWillMount() {
    // this.getLocalStorage();
  }

  handleInputClick(input) {
        this.setState({whatevz:false});

    if (typeof input === "number") {

      if (this.state.resetNext) {
        // reset input if resetNext = true
        this.setState({input: input.toString(), resetNext: false});
      } else {

        // Concatenate input string
        this.setState({input : this.state.input + input.toString()});
      }

    } else if (input === "(-)") {
      // If user input negative (-)
      this.handelNegative();

    } else if (input === ".") {
      // If user input negative (-)
      this.handelComma();

    } else if (input === "C" || input.toUpperCase() === "C") {
      // If user input C
      this.handelClear();

    } else if (input === "=") {
      // If user input =
      this.handelEqual();

    } else if (input === "<") {
      // If user input < (backspace)
      this.handelBackspace();

    } else {
      // If user input +, -, *, /...
      this.setState({resetNext: true});

      if (input !== this.state.math && this.state.math && this.state.math !== "=") {
        // If the user switch between +, -, *, /
        this.handelMathSwitch(input);

      } else {
        this.handelMath(input);
      }

    }
  }

  // ---------------------
  // Handle negative input, only allow one minus key
  // ---------------------
  handelNegative() {
    if (this.state.resetNext) {
      // reset input if resetNext = true
      this.setState({input: "-", resetNext: false});
    } else if (this.state.input.includes("-")) {
      return;
    } else {
        this.setState({input: "-" + this.state.input});
    }
  }

  // ---------------------
  // Handel comma input, only allow one comma key
  // ---------------------
  handelComma() {
    if (this.state.resetNext || this.state.input === "") {
      // reset input if resetNext = true
      this.setState({input: "0.", resetNext: false});
    } else {
      this.setState({input: this.state.input + "."});
    }
  }

  // ---------------------
  // Reset state to original
  // ---------------------
  handelClear() {
    this.setState({
      input: "",
      math: null,
      sum: null,
      resetNext: false,
      firstEntry: true,
    });
  }

  // ---------------------
  // Delete the last number in string, backspace
  // ---------------------
  handelBackspace() {
    this.setState({input: this.state.input.slice(0, -1)});
  }

  // ---------------------
  // Handel equal: handel math, set new state
  // ---------------------
  handelEqual() {
    this.handelMath(this.state.math);
    this.setState({
      firstEntry: true,
      math: "=",
      resetNext: true,
      sum: null,
      whatevz: true
    });
  }

  // ---------------------
  // Handel math switch: handel math and set new state
  // ---------------------
  handelMathSwitch(input) {
    this.handelMath(this.state.math);
    this.setState({
      firstEntry: false,
      math: input,
      resetNext: true
    });
  }

  // ---------------------
  // Save state to localStorage
  // ---------------------
  postLocalStorage() {
    const jsonString = JSON.stringify(this.state);
    localStorage.setItem('calc', jsonString);
  }

  // ---------------------
  // Load state from localStorage
  // ---------------------
  getLocalStorage() {
    const savedState = JSON.parse(localStorage.getItem('calc'));
    this.setState(savedState);
  }

  // ---------------------
  // Handle all math, set new state
  // ---------------------
  handelMath(input) {
    if (this.state.firstEntry) {
      // This only moves the input to state.sum
      this.setState({
        sum: this.state.input,
        math: input,
        firstEntry: false,
      });
    } else {
      switch(input) {
        case "+":
          this.setState({
            input: Addition(this.state.sum, this.state.input).toString(),
            sum: Addition(this.state.sum, this.state.input),
            math: "+",
          });
          break;
        case "-":
          this.setState({
            input: Subtract(this.state.sum, this.state.input).toString(),
            sum: Subtract(this.state.sum, this.state.input),
            math: "-"
          });
          break;
        case "*":
          this.setState({
            input: Multiply(this.state.sum, this.state.input).toString(),
            sum: Multiply(this.state.sum, this.state.input),
            math: "*"
          });
          break;
        case "/":
          this.setState({
            input: Divide(this.state.sum, this.state.input).toString(),
            sum: Divide(this.state.sum, this.state.input),
            math: "/"
          });
          break;
        default:
          break;
      }
    }
  }

  handelChangeTheme() {
    const newTheme = this.state.theme === "red" ? "blue" : "red";
    this.setState({theme: newTheme});
  }

  // React, render to DOM
  render() {
    // this.postLocalStorage();
    return (

        <div className={`calculator ${this.state.theme}`}>

            <button className="themes" onClick={() => this.handelChangeTheme()}>∞</button>

calc

          <div className={`input ${this.state.whatevz ? "animationz" : ""}`}>
            {this.state.input ? this.state.input : 0}

          {/*

            {this.handelHistory()}

 */}

            {this.buttons.map((int) => <Button key={int} onClick={this.handleInputClick.bind(this)} math={this.state.math}>{int}</Button>)}

    );
  }
}
export default App;
<commit_msg>handle comments<commit_after>import React, { Component } from 'react';

// Components
import Button from "./components/button";

// Functions
import Addition from "./functions/addition";
import Subtract from "./functions/subtract";
import Multiply from "./functions/multiply";
import Divide from "./functions/divide";

import './App.css';
import './Color.css';

class App extends Component {

  constructor(props) {
    super(props);

    this.state = {
      input: "",
      math: null,
      sum: null,
      resetNext: false,
      firstEntry: true,
      theme: "red",
    };

    this.buttons = ["C", "(-)", "<", "/", 1, 2, 3, "*", 4, 5, 6, "-", 7 ,8, 9, "+", 0, ".", "="];
  }

  // Run when app is loaded
  componentWillMount() {
    // this.getLocalStorage();
  }

  handleInputClick(input) {
        this.setState({whatevz:false});

    if (typeof input === "number") {

      if (this.state.resetNext) {
        // reset input if resetNext = true
        this.setState({input: input.toString(), resetNext: false});
      } else {

        // Concatenate input string
        this.setState({input : this.state.input + input.toString()});
      }

    } else if (input === "(-)") {
      // If user input negative (-)
      this.handelNegative();

    } else if (input === ".") {
      // If user input negative (-)
      this.handelComma();

    } else if (input === "C" || input.toUpperCase() === "C") {
      // If user input C
      this.handelClear();

    } else if (input === "=") {
      // If user input =
      this.handelEqual();

    } else if (input === "<") {
      // If user input < (backspace)
      this.handelBackspace();

    } else {
      // If user input +, -, *, /...
      this.setState({resetNext: true});

      if (input !== this.state.math && this.state.math && this.state.math !== "=") {
        // If the user switch between +, -, *, /
        this.handelMathSwitch(input);

      } else {
        this.handelMath(input);
      }

    }
  }

  // ---------------------
  // Handle negative input, only allow one minus key
  // ---------------------
  handelNegative() {
    if (this.state.resetNext) {
      // reset input if resetNext = true
      this.setState({input: "-", resetNext: false});
    } else if (this.state.input.includes("-")) {
      return;
    } else {
        this.setState({input: "-" + this.state.input});
    }
  }

  // ---------------------
  // Handle comma input, only allow one comma key
  // ---------------------
  handelComma() {
    if (this.state.resetNext || this.state.input === "") {
      // reset input if resetNext = true
      this.setState({input: "0.", resetNext: false});
    } else {
      this.setState({input: this.state.input + "."});
    }
  }

  // ---------------------
  // Reset state to original
  // ---------------------
  handelClear() {
    this.setState({
      input: "",
      math: null,
      sum: null,
      resetNext: false,
      firstEntry: true,
    });
  }

  // ---------------------
  // Delete the last number in string, backspace
  // ---------------------
  handelBackspace() {
    this.setState({input: this.state.input.slice(0, -1)});
  }

  // ---------------------
  // Handle equal: handle math, set new state
  // ---------------------
  handelEqual() {
    this.handelMath(this.state.math);
    this.setState({
      firstEntry: true,
      math: "=",
      resetNext: true,
      sum: null,
      whatevz: true
    });
  }

  // ---------------------
  // Handle math switch: handle math and set new state
  // ---------------------
  handelMathSwitch(input) {
    this.handelMath(this.state.math);
    this.setState({
      firstEntry: false,
      math: input,
      resetNext: true
    });
  }

  // ---------------------
  // Save state to localStorage
  // ---------------------
  postLocalStorage() {
    const jsonString = JSON.stringify(this.state);
    localStorage.setItem('calc', jsonString);
  }

  // ---------------------
  // Load state from localStorage
  // ---------------------
  getLocalStorage() {
    const savedState = JSON.parse(localStorage.getItem('calc'));
    this.setState(savedState);
  }

  // ---------------------
  // Handle all math, set new state
  // ---------------------
  handelMath(input) {
    if (this.state.firstEntry) {
      // This only moves the input to state.sum
      this.setState({
        sum: this.state.input,
        math: input,
        firstEntry: false,
      });
    } else {
      switch(input) {
        case "+":
          this.setState({
            input: Addition(this.state.sum, this.state.input).toString(),
            sum: Addition(this.state.sum, this.state.input),
            math: "+",
          });
          break;
        case "-":
          this.setState({
            input: Subtract(this.state.sum, this.state.input).toString(),
            sum: Subtract(this.state.sum, this.state.input),
            math: "-"
          });
          break;
        case "*":
          this.setState({
            input: Multiply(this.state.sum, this.state.input).toString(),
            sum: Multiply(this.state.sum, this.state.input),
            math: "*"
          });
          break;
        case "/":
          this.setState({
            input: Divide(this.state.sum, this.state.input).toString(),
            sum: Divide(this.state.sum, this.state.input),
            math: "/"
          });
          break;
        default:
          break;
      }
    }
  }

  handelChangeTheme() {
    const newTheme = this.state.theme === "red" ? "blue" : "red";
    this.setState({theme: newTheme});
  }

  // React, render to DOM
  render() {
    // this.postLocalStorage();
    return (

        <div className={`calculator ${this.state.theme}`}>

            <button className="themes" onClick={() => this.handelChangeTheme()}>∞</button>

calc

          <div className={`input ${this.state.whatevz ? "animationz" : ""}`}>
            {this.state.input ? this.state.input : 0}

          {/*

            {this.handelHistory()}

 */}

            {this.buttons.map((int) => <Button key={int} onClick={this.handleInputClick.bind(this)} math={this.state.math}>{int}</Button>)}

    );
  }
}
export default App;
<|endoftext|>


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

    var version = '1.1.7';

    var seedrandom = require('seedrandom');
    var randomSeed = (new Date()).getTime();

    // must be first
    seedrandom(randomSeed,
    {
        global: true
    });

    var math = require('mathjs');
    var moment = require('moment');

    var fs = require('fs');
    var fsq = require('./fsq');
    var pal = require('./palette');
    var limitTests = require('./limitTests');
    var processes = require('./processes');
    var PNG = require('node-png').PNG;
    var Q = require('q');

    var fp = require('lodash-fp');
    fp.mixin(require('./plus-fp/plus-fp'));

    var twit = require('./tweet-media');

    // smaller image, no tweet
    var isDev = (process.env.TERM_PROGRAM === 'Apple_Terminal');

    //----------- fractal functions

    var fractal = {};

    fractal.zmod = function(functal, z)
    {
        var zmod;

        if (functal.floorz)
        {
            // more blocky
            zmod = math.complex(math.floor(z.re), math.floor(z.im));
        }
        else
        {
            zmod = z;
        }

        return zmod;
    };

    fractal.isDone = function(functal, z)
    {
        // return fp.flow.apply(functal, functal.tests)(z) > functal.limit;

        return fp.flowAll(functal.tests, z) > functal.limit;
    };

    fractal.escapeCount = function(functal, x, y)
    {
        var count = 0;
        var zs = [];

        var z = functal.z(x, y);
        var c = functal.c(x, y);

        zs.push(z);

        var maxCount = functal.maxCount;

        // count how long the iteration takes to break the limit

        while (count < maxCount - 1)
        {
            z = functal.process(fractal.zmod(functal, z), c);

            zs.push(z);

            var done = fractal.isDone(functal, z);

            if (done)
            {
                break;
            }

            count++;
        }

        var result = {
            count: count,
            zs: zs
        };

        return result;
    };

    fractal.process = function(functal, sample)
    {
        // sample is undefined for full resolution
        // use eg 3 to take points a third of the way in

        // store image results
        var data = [];

        // default to every pixel
        var xincr = 1;
        var yincr = 1;

        // if sample, only do a few
        if (sample)
        {
            xincr = functal.width / sample;
            yincr = functal.height / sample;
        }

        // scaled increment
        var fxincr = (functal.range.x2 - functal.range.x1) / functal.width;
        var fyincr = (functal.range.y2 - functal.range.y1) / functal.height;

        // x,y  pixel position
        var x = 0;

        // i,j index into data result matrix
        var i = 0;

        while (x < functal.width)
        {
            // translate to the sub-range
            var fx = functal.range.x1 + fxincr * x;

            data[i] = [];

            var y = 0;
            var j = 0;

            while (y < functal.height)
            {
                var fy = functal.range.y1 + fyincr * y;

                // all inputs & outputs are 0..1
                var result = fractal.escapeCount(functal, fx, fy);

                var adj = functal.modify(functal, result);

                data[i][j] = adj;

                y += yincr;
                j++;
            }

            x += xincr;
            i++;
        }

        return data;
    };

    // ---------- post-escape modififiers

    fractal.modifiers = {};

    // no change
    fractal.modifiers.identity = fp.identity;

    // treat final calc as an angle
    fractal.modifiers.angle = function(functal, result)
    {
        // return 0..1

        var lastz = fp.last(result.zs);

        var val = (math.atan2(lastz.re, lastz.im) / math.pi + 1.0) / 2.0;

        return val;
    };

    // ---------- make a functal

    fractal.make = function(options)
    {
        // async file writing at end
        var deferred = Q.defer();

        var startTime = (new Date()).getTime();

        var functal = {};

        functal.version = options.version();
        functal.seed = randomSeed;
        functal.width = options.width();
        functal.height = options.height();
        functal.maxCount = options.maxCount();
        functal.limit = options.limit();
        functal.range = options.range();
        functal.rangeWidth = functal.range.x2 - functal.range.x1;

        functal.set = {
            name: options.set.name,
            params: options.set.params()
        };
        functal.minStdDev = options.minStdDev();
        functal.z = options.set.z;
        functal.c = options.set.c;

        // tests reduce complex to real so can't be chained, so just use one
        var tests = [fp.wandom(limitTests.tests)];
        functal.testNames = fp.pluck('name', tests);
        functal.tests = fp.pluck('fn', tests);

        var process = fp.wandom(processes.processes);
        functal.processName = process.name;
        functal.process = process.fn;
        functal.pow = options.pow();

        functal.modify = fractal.modifiers.angle;

        functal.floorz = options.floorz();

        // sample
        var sampleCount = 10;
        var data = fractal.process(functal, sampleCount);

        // calc std dev for the sample data
        functal.stdDev = math.std(data);
        functal.uniques = fp.unique(fp.flatten(data)).length;

        // fail if not enough variation in the image sample
        if (functal.stdDev < functal.minStdDev || functal.uniques < sampleCount * sampleCount)
        {
            deferred.reject(functal, data);
        }
        else
        {
            try
            {
                // create fractal
                data = fractal.process(functal);
            }
            catch (ex)
            {
                console.error(ex);
                deferred.reject(functal, data);
            }

            // store time taken
            functal.time = ((new Date()).getTime() - startTime);

            var palette = pal.setPalette();

            fp.extend(fp.omit('colors', palette), functal);

            // save
            if (options.file())
            {
                functal.file = options.file();

                // save options spec
                fsq.writeFile(functal.file + '.json', JSON.stringify(functal, null, 4))
                    .then(function()
                    {
                        // save png
                        return fractal.png(functal, data, palette);

                    }).then(function()
                    {
                        // exit
                        deferred.resolve(functal);
                    });
            }
            else
            {
                // no file required - just exit
                deferred.resolve(functal);
            }
        }

        return deferred.promise;
    };

    // ------------ output to a png image

    fractal.png = function(functal, data, palette)
    {
        var deferred = Q.defer();

        var image = new PNG(
        {
            width: functal.width,
            height: functal.height,
            filterType: -1
        });

        // stretch results over full palette
        var paletteLength = palette.colors.length - 1;

        for (var y = 0; y < image.height; y++)
        {
            for (var x = 0; x < image.width; x++)
            {
                var idx = (image.width * y + x) << 2;

                var index = Math.floor(data[x][y] * paletteLength);

                var rgb = palette.colors[index];

                image.data[idx] = rgb.r;
                image.data[idx + 1] = rgb.g;
                image.data[idx + 2] = rgb.b;
                image.data[idx + 3] = 0xff;
            }
        }

        image.pack().pipe(fs.createWriteStream(functal.file + '.png')).on('close', function()
        {
            deferred.resolve();
        });

        return deferred.promise;

    };

    fractal.setOptions = function()
    {
        var options = {
            version: function()
            {
                // github branch

                return version;
            },

            width: function()
            {
                return (isDev ? 100 : 1024);
            },
            height: function()
            {
                return (isDev ? 100 : 768);
            },
            maxCount: function()
            {
                return 256;
            },
            limit: function()
            {
                return 2;
            },
            file: function()
            {
                // filename with utc time
                return 'functals/functal-' + moment.utc().format('YYYYMMDDHHmmssSSS');
            },
            minStdDev: function()
            {
                return 0.15;
            },
            hue: function()
            {
                return math.random(1);
            },
            saturation: function()
            {
                return 1 - math.pow(math.random(1), 2);
            },
            pow: function()
            {
                return math.random(2, 10);
            },
            floorz: function()
            {
                return math.random() < 0.05;
            }
        };

        // keep selected subarea the same aspect ratio as the image

        options.range = function()
        {
            var aspect = options.width() / options.height();

            // range is from -max to max
            var max = 2;

            var width = fp.random(0.001, 2 * max);

            var x1 = fp.random(-max, max - width);

            var x2 = x1 + width;

            var height = width / aspect;

            var y1 = fp.random(-max, max - height);
            var y2 = y1 + height;

            return {
                x1: x1,
                x2: x2,
                y1: y1,
                y2: y2
            };
        };

        // types of fractals with different initial z & c.
        var sets = [
        {
            name: 'mandelbrot',
            z: function()
            {
                return math.complex(0, 0);
            },
            c: function(x, y)
            {
                return math.complex(x, y);
            },
            params: function()
            {
                return {};
            }
        },
        {
            name: 'julia',
            z: function(x, y)
            {
                return math.complex(x, y);
            },
            c: fp.once(function()
            {
                var cmax = 1.75;

                var c = math.complex(fp.random(-cmax, cmax), fp.random(-cmax, cmax));

                return c;
            }),
            params: function()
            {
                // stored for recreating
                return {
                    c: this.c()
                };
            }

        }];

        // pick a random set type
        options.set = sets[fp.random(0, sets.length - 1)];

        return options;
    };

    // ------------ make a functal

    // use difractalerent options until a fractal with enough variety is found

    // recurse until successful as it's async

    debugger;

    fractal.attempt = function()
    {
        var options = fractal.setOptions();

        fractal.make(options).then(function(functal)
            {
                var msg = '#fractal #functal v' + functal.version + ' calc time ' + moment.duration(functal.time).humanize();

                functal.message = msg;

                console.log('--- success');
                console.log(JSON.stringify(functal, null, 4));

                if (!isDev)
                {
                    twit.tweet(msg, functal.file + '.png');
                }
            },
            function(functal)
            {
                console.log('--- rejected');
                console.log(JSON.stringify(functal, null, 4));
                // retry
                fractal.attempt();
            });
    };

    // kick off

    var devCount = 10;

    var functals = isDev ? devCount : 1;

    fp.range(0, functals).forEach(function()
    {
        fractal.attempt();
    });

}());
<commit_msg>pseudo flow<commit_after>(function()
{
    "use strict";

    var version = '1.1.7';

    var seedrandom = require('seedrandom');
    var randomSeed = (new Date()).getTime();

    // must be first
    seedrandom(randomSeed,
    {
        global: true
    });

    var math = require('mathjs');
    var moment = require('moment');

    var fs = require('fs');
    var fsq = require('./fsq');
    var pal = require('./palette');
    var limitTests = require('./limitTests');
    var processes = require('./processes');
    var PNG = require('node-png').PNG;
    var Q = require('q');

    var fp = require('lodash-fp');
    fp.mixin(require('./plus-fp/plus-fp'));

    var twit = require('./tweet-media');

    // smaller image, no tweet
    var isDev = (process.env.TERM_PROGRAM === 'Apple_Terminal');

    //----------- fractal functions

    var fractal = {};

    fractal.zmod = function(functal, z)
    {
        var zmod;

        if (functal.floorz)
        {
            // more blocky
            zmod = math.complex(math.floor(z.re), math.floor(z.im));
        }
        else
        {
            zmod = z;
        }

        return zmod;
    };

    fractal.isDone = function(functal, zs)
    {
        // return fp.flow.apply(functal, functal.tests)(z) > functal.limit;

        return fp.flowAll(functal.tests, _.last(zs) > functal.limit;
    };

    fractal.escapeCount = function(functal, x, y)
    {
        var count = 0;
        var zs = [];

        var z = functal.z(x, y);
        var c = functal.c(x, y);

        zs.push(z);

        var maxCount = functal.maxCount;

        // count how long the iteration takes to break the limit

        while (count < maxCount - 1)
        {
            z = functal.process(fractal.zmod(functal, z), c);

            zs.push(z);

            var done = fractal.isDone(functal, zs);

            if (done)
            {
                break;
            }

            count++;
        }

        var result = {
            count: count,
            zs: zs
        };

        return result;
    };

    fractal.process = function(functal, sample)
    {
        // sample is undefined for full resolution
        // use eg 3 to take points a third of the way in

        // store image results
        var data = [];

        // default to every pixel
        var xincr = 1;
        var yincr = 1;

        // if sample, only do a few
        if (sample)
        {
            xincr = functal.width / sample;
            yincr = functal.height / sample;
        }

        // scaled increment
        var fxincr = (functal.range.x2 - functal.range.x1) / functal.width;
        var fyincr = (functal.range.y2 - functal.range.y1) / functal.height;

        // x,y  pixel position
        var x = 0;

        // i,j index into data result matrix
        var i = 0;

        while (x < functal.width)
        {
            // translate to the sub-range
            var fx = functal.range.x1 + fxincr * x;

            data[i] = [];

            var y = 0;
            var j = 0;

            while (y < functal.height)
            {
                var fy = functal.range.y1 + fyincr * y;

                // all inputs & outputs are 0..1
                var result = fractal.escapeCount(functal, fx, fy);

                var adj = functal.modify(functal, result);

                data[i][j] = adj;

                y += yincr;
                j++;
            }

            x += xincr;
            i++;
        }

        return data;
    };

    // ---------- post-escape modififiers

    fractal.modifiers = {};

    // no change
    fractal.modifiers.identity = fp.identity;

    // treat final calc as an angle
    fractal.modifiers.angle = function(functal, result)
    {
        // return 0..1

        var lastz = fp.last(result.zs);

        var val = (math.atan2(lastz.re, lastz.im) / math.pi + 1.0) / 2.0;

        return val;
    };

    // ---------- make a functal

    fractal.make = function(options)
    {
        // async file writing at end
        var deferred = Q.defer();

        var startTime = (new Date()).getTime();

        var functal = {};

        functal.version = options.version();
        functal.seed = randomSeed;
        functal.width = options.width();
        functal.height = options.height();
        functal.maxCount = options.maxCount();
        functal.limit = options.limit();
        functal.range = options.range();
        functal.rangeWidth = functal.range.x2 - functal.range.x1;

        functal.set = {
            name: options.set.name,
            params: options.set.params()
        };
        functal.minStdDev = options.minStdDev();
        functal.z = options.set.z;
        functal.c = options.set.c;

        // tests reduce complex to real so can't be chained, so just use one
        var tests = [fp.wandom(limitTests.tests)];
        functal.testNames = fp.pluck('name', tests);
        functal.tests = fp.pluck('fn', tests);

        var process = fp.wandom(processes.processes);
        functal.processName = process.name;
        functal.process = process.fn;
        functal.pow = options.pow();

        functal.modify = fractal.modifiers.angle;

        functal.floorz = options.floorz();

        // sample
        var sampleCount = 10;
        var data = fractal.process(functal, sampleCount);

        // calc std dev for the sample data
        functal.stdDev = math.std(data);
        functal.uniques = fp.unique(fp.flatten(data)).length;

        // fail if not enough variation in the image sample
        if (functal.stdDev < functal.minStdDev || functal.uniques < sampleCount * sampleCount)
        {
            deferred.reject(functal, data);
        }
        else
        {
            try
            {
                // create fractal
                data = fractal.process(functal);
            }
            catch (ex)
            {
                console.error(ex);
                deferred.reject(functal, data);
            }

            // store time taken
            functal.time = ((new Date()).getTime() - startTime);

            var palette = pal.setPalette();

            fp.extend(fp.omit('colors', palette), functal);

            // save
            if (options.file())
            {
                functal.file = options.file();

                // save options spec
                fsq.writeFile(functal.file + '.json', JSON.stringify(functal, null, 4))
                    .then(function()
                    {
                        // save png
                        return fractal.png(functal, data, palette);

                    }).then(function()
                    {
                        // exit
                        deferred.resolve(functal);
                    });
            }
            else
            {
                // no file required - just exit
                deferred.resolve(functal);
            }
        }

        return deferred.promise;
    };

    // ------------ output to a png image

    fractal.png = function(functal, data, palette)
    {
        var deferred = Q.defer();

        var image = new PNG(
        {
            width: functal.width,
            height: functal.height,
            filterType: -1
        });

        // stretch results over full palette
        var paletteLength = palette.colors.length - 1;

        for (var y = 0; y < image.height; y++)
        {
            for (var x = 0; x < image.width; x++)
            {
                var idx = (image.width * y + x) << 2;

                var index = Math.floor(data[x][y] * paletteLength);

                var rgb = palette.colors[index];

                image.data[idx] = rgb.r;
                image.data[idx + 1] = rgb.g;
                image.data[idx + 2] = rgb.b;
                image.data[idx + 3] = 0xff;
            }
        }

        image.pack().pipe(fs.createWriteStream(functal.file + '.png')).on('close', function()
        {
            deferred.resolve();
        });

        return deferred.promise;

    };

    fractal.setOptions = function()
    {
        var options = {
            version: function()
            {
                // github branch

                return version;
            },

            width: function()
            {
                return (isDev ? 100 : 1024);
            },
            height: function()
            {
                return (isDev ? 100 : 768);
            },
            maxCount: function()
            {
                return 256;
            },
            limit: function()
            {
                return 2;
            },
            file: function()
            {
                // filename with utc time
                return 'functals/functal-' + moment.utc().format('YYYYMMDDHHmmssSSS');
            },
            minStdDev: function()
            {
                return 0.15;
            },
            hue: function()
            {
                return math.random(1);
            },
            saturation: function()
            {
                return 1 - math.pow(math.random(1), 2);
            },
            pow: function()
            {
                return math.random(2, 10);
            },
            floorz: function()
            {
                return math.random() < 0.05;
            }
        };

        // keep selected subarea the same aspect ratio as the image

        options.range = function()
        {
            var aspect = options.width() / options.height();

            // range is from -max to max
            var max = 2;

            var width = fp.random(0.001, 2 * max);

            var x1 = fp.random(-max, max - width);

            var x2 = x1 + width;

            var height = width / aspect;

            var y1 = fp.random(-max, max - height);
            var y2 = y1 + height;

            return {
                x1: x1,
                x2: x2,
                y1: y1,
                y2: y2
            };
        };

        // types of fractals with different initial z & c.
        var sets = [
        {
            name: 'mandelbrot',
            z: function()
            {
                return math.complex(0, 0);
            },
            c: function(x, y)
            {
                return math.complex(x, y);
            },
            params: function()
            {
                return {};
            }
        },
        {
            name: 'julia',
            z: function(x, y)
            {
                return math.complex(x, y);
            },
            c: fp.once(function()
            {
                var cmax = 1.75;

                var c = math.complex(fp.random(-cmax, cmax), fp.random(-cmax, cmax));

                return c;
            }),
            params: function()
            {
                // stored for recreating
                return {
                    c: this.c()
                };
            }

        }];

        // pick a random set type
        options.set = sets[fp.random(0, sets.length - 1)];

        return options;
    };

    // ------------ make a functal

    // use difractalerent options until a fractal with enough variety is found

    // recurse until successful as it's async

    debugger;

    fractal.attempt = function()
    {
        var options = fractal.setOptions();

        fractal.make(options).then(function(functal)
            {
                var msg = '#fractal #functal v' + functal.version + ' calc time ' + moment.duration(functal.time).humanize();

                functal.message = msg;

                console.log('--- success');
                console.log(JSON.stringify(functal, null, 4));

                if (!isDev)
                {
                    twit.tweet(msg, functal.file + '.png');
                }
            },
            function(functal)
            {
                console.log('--- rejected');
                console.log(JSON.stringify(functal, null, 4));
                // retry
                fractal.attempt();
            });
    };

    // kick off

    var devCount = 10;

    var functals = isDev ? devCount : 1;

    fp.range(0, functals).forEach(function()
    {
        fractal.attempt();
    });

}());
<|endoftext|>


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

	var root = this,
		Chart = root.Chart,
		helpers = Chart.helpers;

	// The layout service is ver self explanatory.  It's responsible for the layout within a chart.
	// Scales, Legends and Plugins all rely on the layout service and can easily register to be placed anywhere they need
	// It is this service's responsibility of carrying out that layout.
	Chart.layoutService = {
		defaults: {},

		// Register a box to a chartInstance. A box is simply a reference to an object that requires layout. eg. Scales, Legend, Plugins.
		addBox: function(chartInstance, box) {
			if (!chartInstance.boxes) {
				chartInstance.boxes = [];
			}
			chartInstance.boxes.push(box);
		},

		removeBox: function(chartInstance, box) {
			if (!chartInstance.boxes) {
				return;
			}
			chartInstance.boxes.splice(chartInstance.boxes.indexOf(box), 1);
		},

		// The most important function
		update: function(chartInstance, width, height) {

			if (!chartInstance) {
				return;
			}

			var xPadding = width > 30 ? 5 : 2;
			var yPadding = height > 30 ? 5 : 2;

			var leftBoxes = helpers.where(chartInstance.boxes, function(box) {
				return box.options.position == "left";
			});
			var rightBoxes = helpers.where(chartInstance.boxes, function(box) {
				return box.options.position == "right";
			});
			var topBoxes = helpers.where(chartInstance.boxes, function(box) {
				return box.options.position == "top";
			});
			var bottomBoxes = helpers.where(chartInstance.boxes, function(box) {
				return box.options.position == "bottom";
			});

			// Boxes that overlay the chartarea such as the radialLinear scale
			var chartAreaBoxes = helpers.where(chartInstance.boxes, function(box) {
				return box.options.position == "chartArea";
			});

			// Essentially we now have any number of boxes on each of the 4 sides.
			// Our canvas looks like the following.
			// The areas L1 and L2 are the left axes. R1 is the right axis, T1 is the top axis and
			// B1 is the bottom axis
			// There are also 4 quadrant-like locations (left to right instead of clockwise) reserved for chart overlays
			// These locations are single-box locations only, when trying to register a chartArea location that is already taken,
			// an error will be thrown.
			//
			// |----------------------------------------------------|
			// |                  T1 (Full Width)                   |
			// |----------------------------------------------------|
			// |    |    |                 T2                  |    |
			// |    |----|-------------------------------------|----|
			// |    |    | C1 |                           | C2 |    |
			// |    |    |----|                           |----|    |
			// |    |    |                                     |    |
			// | L1 | L2 |           ChartArea (C0)            | R1 |
			// |    |    |                                     |    |
			// |    |    |----|                           |----|    |
			// |    |    | C3 |                           | C4 |    |
			// |    |----|-------------------------------------|----|
			// |    |    |                 B1                  |    |
			// |----------------------------------------------------|
			// |                  B2 (Full Width)                   |
			// |----------------------------------------------------|
			//
			// What we do to find the best sizing, we do the following
			// 1. Determine the minimum size of the chart area.
			// 2. Split the remaining width equally between each vertical axis
			// 3. Split the remaining height equally between each horizontal axis
			// 4. Give each layout the maximum size it can be. The layout will return it's minimum size
			// 5. Adjust the sizes of each axis based on it's minimum reported size.
			// 6. Refit each axis
			// 7. Position each axis in the final location
			// 8. Tell the chart the final location of the chart area
			// 9. Tell any axes that overlay the chart area the positions of the chart area

			// Step 1
			var chartWidth = width / 2; // min 50%
			var chartHeight = height / 2; // min 50%

			chartWidth -= (2 * xPadding);
			chartHeight -= (2 * yPadding);

			// Step 2
			var verticalBoxWidth = (width - chartWidth) / (leftBoxes.length + rightBoxes.length);

			// Step 3
			var horizontalBoxHeight = (height - chartHeight) / (topBoxes.length + bottomBoxes.length);

			// Step 4;
			var minBoxSizes = [];

			// vertical boxes
			helpers.each(leftBoxes, verticalBoxMinSizeFunction);
			helpers.each(rightBoxes, verticalBoxMinSizeFunction);

			function verticalBoxMinSizeFunction(box) {
				var minSize = box.update(verticalBoxWidth, chartHeight);
				minBoxSizes.push({
					horizontal: false,
					minSize: minSize,
					box: box,
				});
			}

			// horizontal boxes
			helpers.each(topBoxes, horizontalBoxMinSizeFunction);
			helpers.each(bottomBoxes, horizontalBoxMinSizeFunction);

			function horizontalBoxMinSizeFunction(box) {
				var minSize = box.update(chartWidth, horizontalBoxHeight);
				minBoxSizes.push({
					horizontal: true,
					minSize: minSize,
					box: box,
				});
			}

			// Step 5
			var maxChartHeight = height - (2 * yPadding);
			var maxChartWidth = width - (2 * xPadding);

			helpers.each(minBoxSizes, function(minimumBoxSize) {
				if (minimumBoxSize.horizontal) {
					maxChartHeight -= minimumBoxSize.minSize.height;
				} else {
					maxChartWidth -= minimumBoxSize.minSize.width;
				}
			});

			// At this point, maxChartHeight and maxChartWidth are the size the chart area could
			// be if the axes are drawn at their minimum sizes.

			// Step 6
			var totalLeftWidth = xPadding;
			var totalRightWidth = xPadding;
			var totalTopHeight = yPadding;
			var totalBottomHeight = yPadding;

			helpers.each(leftBoxes, verticalBoxFitFunction);
			helpers.each(rightBoxes, verticalBoxFitFunction);

			function verticalBoxFitFunction(box) {
				var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minBoxSize) {
					return minBoxSize.box === box;
				});

				if (minBoxSize) {
					box.update(minBoxSize.minSize.width, maxChartHeight);
				}
			}

			// Figure out how much margin is on the left and right of the horizontal axes
			helpers.each(leftBoxes, function(box) {
				totalLeftWidth += box.width;
			});

			helpers.each(rightBoxes, function(box) {
				totalRightWidth += box.width;
			});

			helpers.each(topBoxes, horizontalBoxFitFunction);
			helpers.each(bottomBoxes, horizontalBoxFitFunction);

			function horizontalBoxFitFunction(box) {
				var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minBoxSize) {
					return minBoxSize.box === box;
				});

				var scaleMargin = {
					left: totalLeftWidth,
					right: totalRightWidth,
					top: 0,
					bottom: 0,
				};

				if (minBoxSize) {
					box.update(maxChartWidth, minBoxSize.minSize.height, scaleMargin);
				}
			}

			helpers.each(topBoxes, function(box) {
				totalTopHeight += box.height;
			});

			helpers.each(bottomBoxes, function(box) {
				totalBottomHeight += box.height;
			});

			// Let the left layout know the final margin
			helpers.each(leftBoxes, function(box) {
				var wrapper = helpers.findNextWhere(minBoxSizes, function(wrapper) {
					return wrapper.box === box;
				});

				var scaleMargin = {
					left: 0,
					right: 0,
					top: totalTopHeight,
					bottom: totalBottomHeight
				};

				if (wrapper) {
					box.update(wrapper.minSize.width, maxChartHeight, scaleMargin);
				}
			});

			helpers.each(rightBoxes, function(box) {
				var wrapper = helpers.findNextWhere(minBoxSizes, function(wrapper) {
					return wrapper.box === box;
				});

				var scaleMargin = {
					left: 0,
					right: 0,
					top: totalTopHeight,
					bottom: totalBottomHeight
				};

				if (wrapper) {
					box.update(wrapper.minSize.width, maxChartHeight, scaleMargin);
				}
			});

			// Recalculate because the size of each layout might have changed slightly due to the margins (label rotation for instance)
			totalLeftWidth = xPadding;
			totalRightWidth = xPadding;
			totalTopHeight = yPadding;
			totalBottomHeight = yPadding;

			helpers.each(leftBoxes, function(box) {
				totalLeftWidth += box.width;
			});

			helpers.each(rightBoxes, function(box) {
				totalRightWidth += box.width;
			});

			helpers.each(topBoxes, function(box) {
				totalTopHeight += box.height;
			});
			helpers.each(bottomBoxes, function(box) {
				totalBottomHeight += box.height;
			});

			// Figure out if our chart area changed. This would occur if the dataset layout label rotation
			// changed due to the application of the margins in step 6. Since we can only get bigger, this is safe to do
			// without calling `fit` again
			var newMaxChartHeight = height - totalTopHeight - totalBottomHeight;
			var newMaxChartWidth = width - totalLeftWidth - totalRightWidth;

			if (newMaxChartWidth !== maxChartWidth || newMaxChartHeight !== maxChartHeight) {
				helpers.each(leftBoxes, function(box) {
					box.height = newMaxChartHeight;
				});

				helpers.each(rightBoxes, function(box) {
					box.height = newMaxChartHeight;
				});

				helpers.each(topBoxes, function(box) {
					box.width = newMaxChartWidth;
				});

				helpers.each(bottomBoxes, function(box) {
					box.width = newMaxChartWidth;
				});

				maxChartHeight = newMaxChartHeight;
				maxChartWidth = newMaxChartWidth;
			}

			// Step 7 - Position the boxes
			var left = xPadding;
			var top = yPadding;
			var right = 0;
			var bottom = 0;

			helpers.each(leftBoxes, verticalBoxPlacer);
			helpers.each(topBoxes, horizontalBoxPlacer);

			// Account for chart width and height
			left += maxChartWidth;
			top += maxChartHeight;

			helpers.each(rightBoxes, verticalBoxPlacer);
			helpers.each(bottomBoxes, horizontalBoxPlacer);

			function verticalBoxPlacer(box) {
				box.left = left;
				box.right = left + box.width;
				box.top = totalTopHeight;
				box.bottom = totalTopHeight + maxChartHeight;

				// Move to next point
				left = box.right;
			}

			function horizontalBoxPlacer(box) {
				box.left = totalLeftWidth;
				box.right = totalLeftWidth + maxChartWidth;
				box.top = top;
				box.bottom = top + box.height;

				// Move to next point
				top = box.bottom;
			}

			// Step 8
			chartInstance.chartArea = {
				left: totalLeftWidth,
				top: totalTopHeight,
				right: totalLeftWidth + maxChartWidth,
				bottom: totalTopHeight + maxChartHeight,
			};

			// Step 9
			helpers.each(chartAreaBoxes, function(box) {
				box.left = chartInstance.chartArea.left;
				box.top = chartInstance.chartArea.top;
				box.right = chartInstance.chartArea.right;
				box.bottom = chartInstance.chartArea.bottom;

				box.update(maxChartWidth, maxChartHeight);
			});
		}
	};

}).call(this);
<commit_msg>Layout Service readability & reorganization<commit_after>(function() {
	"use strict";

	var root = this,
		Chart = root.Chart,
		helpers = Chart.helpers;

	// The layout service is ver self explanatory.  It's responsible for the layout within a chart.
	// Scales, Legends and Plugins all rely on the layout service and can easily register to be placed anywhere they need
	// It is this service's responsibility of carrying out that layout.
	Chart.layoutService = {
		defaults: {},

		// Register a box to a chartInstance. A box is simply a reference to an object that requires layout. eg. Scales, Legend, Plugins.
		addBox: function(chartInstance, box) {
			if (!chartInstance.boxes) {
				chartInstance.boxes = [];
			}
			chartInstance.boxes.push(box);
		},

		removeBox: function(chartInstance, box) {
			if (!chartInstance.boxes) {
				return;
			}
			chartInstance.boxes.splice(chartInstance.boxes.indexOf(box), 1);
		},

		// The most important function
		update: function(chartInstance, width, height) {

			if (!chartInstance) {
				return;
			}

			var xPadding = width > 30 ? 5 : 2;
			var yPadding = height > 30 ? 5 : 2;

			var leftBoxes = helpers.where(chartInstance.boxes, function(box) {
				return box.options.position == "left";
			});
			var rightBoxes = helpers.where(chartInstance.boxes, function(box) {
				return box.options.position == "right";
			});
			var topBoxes = helpers.where(chartInstance.boxes, function(box) {
				return box.options.position == "top";
			});
			var bottomBoxes = helpers.where(chartInstance.boxes, function(box) {
				return box.options.position == "bottom";
			});

			// Boxes that overlay the chartarea such as the radialLinear scale
			var chartAreaBoxes = helpers.where(chartInstance.boxes, function(box) {
				return box.options.position == "chartArea";
			});

			// Essentially we now have any number of boxes on each of the 4 sides.
			// Our canvas looks like the following.
			// The areas L1 and L2 are the left axes. R1 is the right axis, T1 is the top axis and
			// B1 is the bottom axis
			// There are also 4 quadrant-like locations (left to right instead of clockwise) reserved for chart overlays
			// These locations are single-box locations only, when trying to register a chartArea location that is already taken,
			// an error will be thrown.
			//
			// |----------------------------------------------------|
			// |                  T1 (Full Width)                   |
			// |----------------------------------------------------|
			// |    |    |                 T2                  |    |
			// |    |----|-------------------------------------|----|
			// |    |    | C1 |                           | C2 |    |
			// |    |    |----|                           |----|    |
			// |    |    |                                     |    |
			// | L1 | L2 |           ChartArea (C0)            | R1 |
			// |    |    |                                     |    |
			// |    |    |----|                           |----|    |
			// |    |    | C3 |                           | C4 |    |
			// |    |----|-------------------------------------|----|
			// |    |    |                 B1                  |    |
			// |----------------------------------------------------|
			// |                  B2 (Full Width)                   |
			// |----------------------------------------------------|
			//
			// What we do to find the best sizing, we do the following
			// 1. Determine the minimum size of the chart area.
			// 2. Split the remaining width equally between each vertical axis
			// 3. Split the remaining height equally between each horizontal axis
			// 4. Give each layout the maximum size it can be. The layout will return it's minimum size
			// 5. Adjust the sizes of each axis based on it's minimum reported size.
			// 6. Refit each axis
			// 7. Position each axis in the final location
			// 8. Tell the chart the final location of the chart area
			// 9. Tell any axes that overlay the chart area the positions of the chart area

			// Step 1
			var chartWidth = width - (2 * xPadding);
			var chartHeight = height - (2 * yPadding);
			var chartAreaWidth = chartWidth / 2; // min 50%
			var chartAreaHeight = chartHeight / 2; // min 50%

			// Step 2
			var verticalBoxWidth = (width - chartAreaWidth) / (leftBoxes.length + rightBoxes.length);

			// Step 3
			var horizontalBoxHeight = (height - chartAreaHeight) / (topBoxes.length + bottomBoxes.length);

			// Step 4
			var minBoxSizes = [];

			helpers.each(leftBoxes.concat(rightBoxes, topBoxes, bottomBoxes), getMinimumBoxSize);

			function getMinimumBoxSize(box) {
				var minSize;
				var isHorizontal = box.isHorizontal();

				if (isHorizontal) {
					minSize = box.update(chartWidth, horizontalBoxHeight);
				} else {
					minSize = box.update(verticalBoxWidth, chartAreaHeight);
				}
				minBoxSizes.push({
					horizontal: isHorizontal,
					minSize: minSize,
					box: box,
				});
			}

			// Step 5
			var maxChartAreaWidth = chartWidth;
			var maxChartAreaHeight = chartHeight;

			helpers.each(minBoxSizes, function(minimumBoxSize) {
				if (minimumBoxSize.horizontal) {
					maxChartAreaHeight -= minimumBoxSize.minSize.height;
				} else {
					maxChartAreaWidth -= minimumBoxSize.minSize.width;
				}
			});

			// At this point, maxChartAreaHeight and maxChartAreaWidth are the size the chart area could
			// be if the axes are drawn at their minimum sizes.

			// Step 6
			var totalLeftBoxesWidth = xPadding;
			var totalRightBoxesWidth = xPadding;
			var totalTopBoxesHeight = yPadding;
			var totalBottomBoxesHeight = yPadding;

			// Update, and calculate the left and right margins for the horizontal boxes
			helpers.each(leftBoxes.concat(rightBoxes), fitBox);

			helpers.each(leftBoxes, function(box) {
				totalLeftBoxesWidth += box.width;
			});

			helpers.each(rightBoxes, function(box) {
				totalRightBoxesWidth += box.width;
			});

			// Set the Left and Right margins for the horizontal boxes
			helpers.each(topBoxes.concat(bottomBoxes), fitBox);

			function fitBox(box) {

				var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minBoxSize) {
					return minBoxSize.box === box;
				});

				if (box.isHorizontal() && minBoxSize) {
					var scaleMargin = {
						left: totalLeftBoxesWidth,
						right: totalRightBoxesWidth,
						top: 0,
						bottom: 0,
					};

					box.update(chartWidth, minBoxSize.minSize.height, scaleMargin);
				} else {
					box.update(minBoxSize.minSize.width, maxChartAreaHeight);
				}
			}

			// Figure out how much margin is on the top and bottom of the vertical boxes
			helpers.each(topBoxes, function(box) {
				totalTopBoxesHeight += box.height;
			});

			helpers.each(bottomBoxes, function(box) {
				totalBottomBoxesHeight += box.height;
			});

			// Let the left layout know the final margin
			helpers.each(leftBoxes.concat(rightBoxes), finalFitVerticalBox);

			function finalFitVerticalBox(box) {
				var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minBoxSize) {
					return minBoxSize.box === box;
				});

				var scaleMargin = {
					left: 0,
					right: 0,
					top: totalTopBoxesHeight,
					bottom: totalBottomBoxesHeight
				};

				if (minBoxSize) {
					box.update(minBoxSize.minSize.width, maxChartAreaHeight, scaleMargin);
				}
			}

			// Recalculate because the size of each layout might have changed slightly due to the margins (label rotation for instance)
			totalLeftBoxesWidth = xPadding;
			totalRightBoxesWidth = xPadding;
			totalTopBoxesHeight = yPadding;
			totalBottomBoxesHeight = yPadding;

			helpers.each(leftBoxes, function(box) {
				totalLeftBoxesWidth += box.width;
			});

			helpers.each(rightBoxes, function(box) {
				totalRightBoxesWidth += box.width;
			});

			helpers.each(topBoxes, function(box) {
				totalTopBoxesHeight += box.height;
			});
			helpers.each(bottomBoxes, function(box) {
				totalBottomBoxesHeight += box.height;
			});

			// Figure out if our chart area changed. This would occur if the dataset layout label rotation
			// changed due to the application of the margins in step 6. Since we can only get bigger, this is safe to do
			// without calling `fit` again
			var newMaxChartAreaHeight = height - totalTopBoxesHeight - totalBottomBoxesHeight;
			var newMaxChartAreaWidth = width - totalLeftBoxesWidth - totalRightBoxesWidth;

			if (newMaxChartAreaWidth !== maxChartAreaWidth || newMaxChartAreaHeight !== maxChartAreaHeight) {
				helpers.each(leftBoxes, function(box) {
					box.height = newMaxChartAreaHeight;
				});

				helpers.each(rightBoxes, function(box) {
					box.height = newMaxChartAreaHeight;
				});

				helpers.each(topBoxes, function(box) {
					box.width = newMaxChartAreaWidth;
				});

				helpers.each(bottomBoxes, function(box) {
					box.width = newMaxChartAreaWidth;
				});

				maxChartAreaHeight = newMaxChartAreaHeight;
				maxChartAreaWidth = newMaxChartAreaWidth;
			}

			// Step 7 - Position the boxes
			var left = xPadding;
			var top = yPadding;
			var right = 0;
			var bottom = 0;

			helpers.each(leftBoxes.concat(topBoxes), placeBox);

			// Account for chart width and height
			left += maxChartAreaWidth;
			top += maxChartAreaHeight;

			helpers.each(rightBoxes, placeBox);
			helpers.each(bottomBoxes, placeBox);

			function placeBox(box) {
				if (box.isHorizontal()) {
					box.left = xPadding;
					box.right = width - xPadding;
					box.top = top;
					box.bottom = top + box.height;

					// Move to next point
					top = box.bottom;

				} else {

					box.left = left;
					box.right = left + box.width;
					box.top = totalTopBoxesHeight;
					box.bottom = totalTopBoxesHeight + maxChartAreaHeight;

					// Move to next point
					left = box.right;
				}
			}

			// Step 8
			chartInstance.chartArea = {
				left: totalLeftBoxesWidth,
				top: totalTopBoxesHeight,
				right: totalLeftBoxesWidth + maxChartAreaWidth,
				bottom: totalTopBoxesHeight + maxChartAreaHeight,
			};

			// Step 9
			helpers.each(chartAreaBoxes, function(box) {
				box.left = chartInstance.chartArea.left;
				box.top = chartInstance.chartArea.top;
				box.right = chartInstance.chartArea.right;
				box.bottom = chartInstance.chartArea.bottom;

				box.update(maxChartAreaWidth, maxChartAreaHeight);
			});
		}
	};

}).call(this);
<|endoftext|>