<commit_before>CKEDITOR.dialog.add('pbcodeDialog', function ( editor ) {

// load JS file
var head = document.getElementsByTagName('HEAD').item(0);
var script= document.createElement("script");
script.type = "text/javascript";
script.src = CKEDITOR.plugins.getPath('pbcode') + "dialogs/ace/ace.js";
head.appendChild(script);

// load CSS file
var link  = document.createElement('link');
link.rel  = 'stylesheet';
link.type = 'text/css';
link.href = CKEDITOR.plugins.getPath('pbcode') + "dialogs/style.css";
link.media = 'all';
head.appendChild(link);

// default values of the plugin
if(editor.config.pbcode.class == undefined)
	editor.config.pbcode.class = "prettyprint linenums";
if(editor.config.pbcode.mode == undefined)
	editor.config.pbcode.mode =  [ ['PHP', 'php'], ['HTML', 'html'], ['CSS', 'css'] ]
if(editor.config.pbcode.default == undefined)
	editor.config.pbcode.default =  editor.config.pbcode.mode[0][1];
if(editor.config.pbcode.theme == undefined)
	editor.config.pbcode.theme = 'textmate';

var AceEditor;

return {
		// Basic properties of the dialog window: title, minimum size.
		title: editor.lang.pbcode.title,
		minWidth: 600,
		minHeight: 400,

		// Dialog window contents definition.
		contents:
		[{
			id		 : 'code-container',
			label	 : editor.lang.pbcode.tabCode,
			elements :
			[{
				type    : 'select',
				id      : 'code-select',
				items   : editor.config.pbcode.mode,
				default : editor.config.pbcode.default,
				setup   : function(element) {
					this.setValue(element.getAttribute("data-language"));
				},
				commit : function(element) {
					element.setAttribute("data-language", this.getValue());
				},
				onChange: function(api) {
					AceEditor.getSession().setMode("ace/mode/" + this.getValue());
				}
			},
			{
				type  : 'html',
				html  : '

',
				setup : function(element) {
					// get the value of the editor
					AceEditor.setValue(element.getHtml().replace('
', '\n'));
				},
				commit : function(element) {
					element.setText(AceEditor.getValue());
				}
			}]
		}],
		onLoad: function() {
			// we get the #code div and style it
			var code = document.getElementById('code');
			code.style.width = '600px';
			code.style.height = '380px';
			code.style.position = 'relative';

			// we load the ACE plugin to our div
			AceEditor = ace.edit("code");
			AceEditor.getSession().setMode("ace/mode/php");
			AceEditor.setTheme("ace/theme/" + editor.config.pbcode.theme);
		},
		onShow : function() {
			// get the select
			var selection = editor.getSelection();
			// get the entire element
			var element = selection.getStartElement();

			// looking for the pre parent tag
			if(element)
				element = element.getAscendant('pre', true);

			// if there is no pre tag, it is an addition. Therefore, it is an edition
			if(!element || element.getName() != 'pre') {
				element = editor.document.createElement('pre');
				this.insertMode = true;
			}
			else
				this.insertMode = false;

			// get the element to fill the inputs
			this.element = element;

			// we empty the editor
			AceEditor.setValue('');

			// we fill the inputs
			if(!this.insertMode)
				this.setupContent(this.element);
		},
		// This method is invoked once a user clicks the OK button, confirming the dialog.
		onOk: function() {
			var dialog = this,
				pre = this.element;

			// we get the value of the inputs
			this.commitContent(pre);

			// we add a new pre tag into ckeditor editor
			if(this.insertMode) {
				pre.setAttribute('class', editor.config.pbcode.class);
				editor.insertElement(pre);
			}

		}
	};

});<commit_msg>version 1.0.0<commit_after>CKEDITOR.dialog.add('pbcodeDialog', function ( editor ) {

// load JS file
var head = document.getElementsByTagName('HEAD').item(0);
var script= document.createElement("script");
script.type = "text/javascript";
script.src = CKEDITOR.plugins.getPath('pbcode') + "dialogs/ace/ace.js";
head.appendChild(script);

// load CSS file
var link  = document.createElement('link');
link.rel  = 'stylesheet';
link.type = 'text/css';
link.href = CKEDITOR.plugins.getPath('pbcode') + "dialogs/style.css";
link.media = 'all';
head.appendChild(link);

// default values of the plugin
if(editor.config.pbcode.class == undefined)
	editor.config.pbcode.class = "prettyprint linenums";
if(editor.config.pbcode.mode == undefined)
	editor.config.pbcode.mode =  [ ['PHP', 'php'], ['HTML', 'html'], ['CSS', 'css'] ]
if(editor.config.pbcode.default == undefined)
	editor.config.pbcode.default =  editor.config.pbcode.mode[0][1];
if(editor.config.pbcode.theme == undefined)
	editor.config.pbcode.theme = 'textmate';

var AceEditor;

return {
		// Basic properties of the dialog window: title, minimum size.
		title: editor.lang.pbcode.title,
		minWidth: 600,
		minHeight: 400,

		// Dialog window contents definition.
		contents:
		[{
			id		 : 'code-container',
			label	 : editor.lang.pbcode.tabCode,
			elements :
			[{
				type    : 'select',
				id      : 'code-select',
				items   : editor.config.pbcode.mode,
				default : editor.config.pbcode.default,
				setup   : function(element) {
					this.setValue(element.getAttribute("data-language"));
				},
				commit : function(element) {
					element.setAttribute("data-language", this.getValue());
				},
				onChange: function(api) {
					AceEditor.getSession().setMode("ace/mode/" + this.getValue());
				}
			},
			{
				type  : 'html',
				html  : '

',
				setup : function(element) {
					// get the value of the editor
					AceEditor.setValue(element.getHtml().replace('
', '\n'));
				},
				commit : function(element) {
					element.setText(AceEditor.getValue());
				}
			}]
		}],
		onLoad: function() {
			// we get the #code div and style it
			var code = document.getElementById('code');
			code.style.width = '600px';
			code.style.height = '380px';
			code.style.position = 'relative';

			// we load the ACE plugin to our div
			AceEditor = ace.edit("code");
			AceEditor.getSession().setMode("ace/mode/" + editor.config.pbcode.default);
			AceEditor.setTheme("ace/theme/" + editor.config.pbcode.theme);
		},
		onShow : function() {
			// get the select
			var selection = editor.getSelection();
			// get the entire element
			var element = selection.getStartElement();

			// looking for the pre parent tag
			if(element)
				element = element.getAscendant('pre', true);

			// if there is no pre tag, it is an addition. Therefore, it is an edition
			if(!element || element.getName() != 'pre') {
				element = editor.document.createElement('pre');
				this.insertMode = true;
			}
			else
				this.insertMode = false;

			// get the element to fill the inputs
			this.element = element;

			// we empty the editor
			AceEditor.setValue('');

			// we fill the inputs
			if(!this.insertMode)
				this.setupContent(this.element);
		},
		// This method is invoked once a user clicks the OK button, confirming the dialog.
		onOk: function() {
			var dialog = this,
				pre = this.element;

			// we get the value of the inputs
			this.commitContent(pre);

			// we add a new pre tag into ckeditor editor
			if(this.insertMode) {
				pre.setAttribute('class', editor.config.pbcode.class);
				editor.insertElement(pre);
			}

		}
	};

});<|endoftext|>


<commit_before>module.exports = {
    sslConnectInterceptor: (req, cltSocket, head) => true,
    caCertPath: '/Users/wuchangming834/node-mitmproxy/bk/node-mitmproxy.ca.crt',
    caKeyPath: '/Users/wuchangming834/node-mitmproxy/bk/node-mitmproxy.ca.key.pem'
}
<commit_msg>update path<commit_after>module.exports = {
    sslConnectInterceptor: (req, cltSocket, head) => true,
    caCertPath: '/Users/wuchangming/node-mitmproxy/bk/node-mitmproxy.ca.crt',
    caKeyPath: '/Users/wuchangming/node-mitmproxy/bk/node-mitmproxy.ca.key.pem'
}
<|endoftext|>


<commit_before>#!/usr/bin/node

var net = require('net');

clients = []
servers = []

//console.log(clients);

function bye(c) {
 if (clients.indexOf(c) > -1) {
    index = clients.indexOf(c);
    clients.splice(index, 1);
    //console.log("Clients: " + clients.length);
  } else if (servers.indexOf(c) > -1) {
    index = servers.indexOf(c);
    servers.splice(index, 1);
    //console.log("Servers: " + servers.length);
  }
};

server = net.createServer(function(c) {
  oldData = '';
  c.on('data', function(data) {
    //console.log(data.toString().trim());
    if (data.toString().trim() == 'S') {
      servers.push(c);
      //console.log(servers.length);
    } else if (data.toString().trim() == 'C') {
      clients.push(c);
      //console.log(clients.length);
    } else {
      if (data.toString()[data.length-1] == '\n') {
        allData = oldData + data;
        if (oldData != '') {
          console.log("fixed some data");
          console.log(allData.length);
        }
        oldData = '';
        //console.log ('complete data ' + data.length );
        if (servers.indexOf(c) > -1) {
          clients.forEach(function (sock) {
            sock.write(allData);
          })
        } else if (clients.indexOf(c) > -1) {
          servers.forEach(function (sock) {
            sock.write(allData);
          });
        } else {
          c.write('Servers: ' + servers.length + "\nClients: " + clients.length + "\n");
        };
      } else {
        oldData = oldData + data
        //console.log ('incomplete data ' + data.length );
        //console.log(data.toString());
      };
    };
  });
  c.on('end', function() {
    bye(c);
  });
  c.on('error', function() {
    c.end();
    bye(c);
  });

});

server.listen(5555);
<commit_msg>remove console log messages, cleanup<commit_after>#!/usr/bin/node

var net = require('net');

clients = []
servers = []
commandOnlyClients = []

function bye(c) {
 if (clients.indexOf(c) > -1) {
    index = clients.indexOf(c);
    clients.splice(index, 1);
  } else if (servers.indexOf(c) > -1) {
    index = servers.indexOf(c);
    servers.splice(index, 1);
  }
};

server = net.createServer(function(c) {
  oldData = '';
  c.on('data', function(data) {
    if (data.toString().trim() == 'S') {
      servers.push(c);
    } else if (data.toString().trim() == 'C') {
      clients.push(c);
    } else if (data.toString().trim() == 'CO') {
      console.log('commandy');
      commandOnlyClients.push(c);
    } else {
      if (data.toString()[data.length-1] == '\n') {
        //assembles data into full size chunks
        allData = oldData + data;
        oldData = '';
        if (servers.indexOf(c) > -1) {
          clients.forEach(function (sock) {
            sock.write(allData);
          })
        } else if (clients.indexOf(c) > -1) {
          servers.forEach(function (sock) {
            sock.write(allData);
          });
        } else {
          c.write('Servers: ' + servers.length + "\nClients: " + clients.length + "Command only Clients: " + commandOnlyClients.lentgh + "\n");
        };
      } else {
        oldData = oldData + data
      };
    };
  });
  c.on('end', function() {
    bye(c);
  });
  c.on('error', function() {
    c.end();
    bye(c);
  });

});

server.listen(5555);
<|endoftext|>


<commit_before>/**
 * Copyright (c) Jonathan Cardoso Machado. All Rights Reserved.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

// Example showing how one could download only the start of a big file
// using streams with the`curly` async fn

const fs = require('fs')

const { curly, CurlCode } = require('../dist')

const run = async () => {
  const {
    data: stream
  } = await curly.get('https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_1mb.mp4', {
    // we want the unparsed binary response to be returned as a stream to us
    curlyStreamResponse: true,
    curlyResponseBodyParsers: false
  })

  // we are going to write the response stream to this file
  const writableStream = fs.createWriteStream('big_buck_bunny_720p_1mb.mp4')

  let count = 0;
  stream.on('data', (chunk) => {
    count += chunk.length
    console.info("downloaded", Math.floor(count / 1000), "KB")
    // abort after 50KB
    if (count >= 65536) {
      console.info("abort download")
      stream.destroy()
    }
  })
  stream.on('error', (err) => {
    if (err.isCurlError && err.code === CurlCode.CURLE_ABORTED_BY_CALLBACK) {
      // this is expected
    } else {
      throw err
    }
  })
  stream.pipe(writableStream)
}

run()
  .then(() => console.log('finished!'))
  .catch((error) => {
    console.error('error: ', error)
  })
<commit_msg>ci: fix lint<commit_after>/**
 * Copyright (c) Jonathan Cardoso Machado. All Rights Reserved.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

// Example showing how one could download only the start of a big file
// using streams with the`curly` async fn

const fs = require('fs')

const { curly, CurlCode } = require('../dist')

const run = async () => {
  const { data: stream } = await curly.get(
    'https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_1mb.mp4',
    {
      // we want the unparsed binary response to be returned as a stream to us
      curlyStreamResponse: true,
      curlyResponseBodyParsers: false,
    },
  )

  // we are going to write the response stream to this file
  const writableStream = fs.createWriteStream('big_buck_bunny_720p_1mb.mp4')

  let count = 0
  stream.on('data', (chunk) => {
    count += chunk.length
    console.info('downloaded', Math.floor(count / 1000), 'KB')
    // abort after 50KB
    if (count >= 65536) {
      console.info('abort download')
      stream.destroy()
    }
  })
  stream.on('error', (err) => {
    if (err.isCurlError && err.code === CurlCode.CURLE_ABORTED_BY_CALLBACK) {
      // this is expected
    } else {
      throw err
    }
  })
  stream.pipe(writableStream)
}

run()
  .then(() => console.log('finished!'))
  .catch((error) => {
    console.error('error: ', error)
  })
<|endoftext|>


<commit_before>var models = require('./../app/models')
  , db = require('../db').connect()
  , elasticSearch = require('./elastic-search-client.js')
  , async = require('async')

var startCheckingPosts = function() {
  db.keys('post:*', function(err, postsIdKeys) {
    async.forEach(postsIdKeys
      ,function(postsIdKey, callback) {
        var postId;
        postsIdKey = postsIdKey.replace(/post:/, '');
        if (!/:(\w)+/.test(postsIdKey)) {
          postId = postsIdKey;

          models.Post.findById(postId, function(err, post) {
            if (post) {
              post.toJSON({ select: ['id', 'body', 'createdBy', 'attachments', 'comments', 'createdAt', 'updatedAt', 'likes', 'timelineId'],
                  createdBy: { select: ['id', 'username'] },
                  comments: { select: ['id', 'body', 'createdBy'],
                    createdBy: { select: ['id', 'username'] } },
                  likes: { select: ['id', 'username']}
                },
                function(err, json) {
                  checkIndex({
                    index: 'pepyatka',
                    type: 'post',
                    element: json
                  }, function(err){
                    callback(err);
                  });
                });
            }
          })
        } else {
          callback(null)
        }
      }
      , function(err) {
        //TODO Fix this. The message is displayed before the reindexation is complete
        console.log('Reindexation was complete');
    });
  });
}

var startCheckingIndexes = function() {
  startCheckingPosts();
}

var checkIndex = function(dbObject, callback) {
  var qryObj = {
    "query" : {
        "term" : { "_id" : dbObject.element.id }
    }
  };

  elasticSearch.elasticSearchClient.search(dbObject.index, dbObject.type, qryObj)
    .on('data', function(data) {
      var json =  JSON.parse(data);
      var result = elasticSearch.parse(json)[0];
      if (result){
        if (!isEqualElements(dbObject.element, result)) {
          elasticSearch.updateElement(dbObject.index, dbObject.type, dbObject.element);
        }
      } else {
          elasticSearch.indexElement(dbObject.index, dbObject.type, dbObject.element);
      }
    })
    .on('done', function() {
      callback(null)
    })
    .on('error', function(error) {
      console.log(error)
      callback(error)
    })
    .exec();
}

var isEqualArrays = function(firstArray, secondArray) {
  var isEqual;
  if (Array.isArray(firstArray) && Array.isArray(secondArray)) {
    isEqual = firstArray.length == secondArray.length;
    if (isEqual) {
      var i = 0;
      firstArray.forEach(function(element) {
        if (isEqual){
          isEqual = isEqualElements(element, secondArray[i++]);
        }
      })
    }
  }

  return isEqual;
};

var isEqualObjects = function(firstObject, secondObject) {
  var isEqual;
  var checkedProperties = [];
  if (typeof firstObject == 'object' && typeof secondObject == 'object') {
    isEqual = true;
    for(var property in firstObject) {
      if (isEqual) {
        checkedProperties.push(property);
        isEqual = isEqualElements(firstObject[property], secondObject[property]);
      }
    }
    if (isEqual) {
      for(var property in secondObject) {
        if (isEqual) {
          if (checkedProperties.indexOf(property) == -1) {
            isEqual = false;
          }
        }
      }
    }
  }

  return isEqual;
}

var isEqualElements = function(firstElement, secondElement) {
  var isEqual;
  if (typeof firstElement == 'object' && typeof secondElement == 'object') {
    if (Array.isArray(firstElement) && Array.isArray(secondElement)) {
      isEqual = isEqualArrays(firstElement, secondElement);
    } else{
      if (Array.isArray(firstElement) || Array.isArray(secondElement)) {
        isEqual = false;
      } else {
        isEqual = isEqualObjects(firstElement, secondElement);
      }
    }
  } else {
    isEqual = firstElement == secondElement;
  }

  return isEqual;
}

exports.startInspection = function() {
  startCheckingIndexes();
}
<commit_msg>Implements reindexation for deleted posts.<commit_after>var models = require('./../app/models')
  , db = require('../db').connect()
  , elasticSearch = require('./elastic-search-client.js')
  , async = require('async')

var startCheckingPosts = function() {
  var startCheckingExistingPosts = function(callback) {
    db.keys('post:*', function(err, postsIdKeys) {
      async.forEach(postsIdKeys
        ,function(postsIdKey, callback) {
          var postId;
          postsIdKey = postsIdKey.replace(/post:/, '');
          if (!/:(\w)+/.test(postsIdKey)) {
            postId = postsIdKey;

            models.Post.findById(postId, function(err, post) {
              if (post) {
                post.toJSON({ select: ['id', 'body', 'createdBy', 'attachments', 'comments', 'createdAt', 'updatedAt', 'likes', 'timelineId'],
                    createdBy: { select: ['id', 'username'] },
                    comments: { select: ['id', 'body', 'createdBy'],
                      createdBy: { select: ['id', 'username'] } },
                    likes: { select: ['id', 'username']}
                  },
                  function(err, json) {
                    checkIndex({
                      index: 'pepyatka',
                      type: 'post',
                      element: json
                    }, function(err){
                      callback(err);
                    });
                  });
              }
            })
          } else {
            callback(null)
          }
        }
        , function(err) {
          callback()
        });
    });
  }

  var startChekingDeletedPosts = function(callback) {
    var checkDeletedPosts = function(fromNumber) {
      var size = 25
      var queryObject = {
        "size" : size,
        "from" : fromNumber,
        "query" : {
          "wildcard" : { "id" : '?*' } //It doesn't work with '_id'
        }}

      elasticSearch.elasticSearchClient.search('pepyatka', 'post', queryObject)
        .on('data', function(data) {
          var json =  JSON.parse(data);
          var searchedElements = elasticSearch.parse(json)
          if(searchedElements.length == 0) callback()

          async.forEach(searchedElements, function(post, callback) {
              checkDbElement('pepyatka', 'post', post.id)
              callback()
            },
            function(err) {
              checkDeletedPosts(fromNumber + size)
            })
        })
        .on('done', function() {
        })
        .on('error', function(error) {
          console.log(error)
        })
        .exec();
    }

    checkDeletedPosts(0)
  }

  async.parallel([
      function(callback) {
        startCheckingExistingPosts(callback)
      },
      function(callback) {
        startChekingDeletedPosts(callback)
      }],
    function(err) {
      if(err) console.log(err)
      else console.log('Reindexation was complete');//TODO Fix this. The message is displayed before the reindexation is complete
  })
}

var startCheckingIndexes = function() {
  startCheckingPosts();
}

var checkDbElement = function(index, type, elementId) {
  switch (type) {
    case 'post':
      models.Post.findById(elementId, function(err, post) {
        if (post) return

        elasticSearch.deleteElement(index, type, elementId)
      })
      break
  }
}

var checkIndex = function(dbObject, callback) {
  var qryObj = {
    "query" : {
        "term" : { "_id" : dbObject.element.id } //It doesn't work with 'id'
    }
  };

  elasticSearch.elasticSearchClient.search(dbObject.index, dbObject.type, qryObj)
    .on('data', function(data) {
      var json =  JSON.parse(data);
      var result = elasticSearch.parse(json)[0];
      if (result){
        if (!isEqualElements(dbObject.element, result)) {
          elasticSearch.updateElement(dbObject.index, dbObject.type, dbObject.element);
        }
      } else {
          elasticSearch.indexElement(dbObject.index, dbObject.type, dbObject.element);
      }
    })
    .on('done', function() {
      callback(null)
    })
    .on('error', function(error) {
      console.log(error)
      callback(error)
    })
    .exec();
}

var isEqualElements = function(firstElement, secondElement) {
  var isEqualArrays = function(firstArray, secondArray) {
    var isEqual;
    if (Array.isArray(firstArray) && Array.isArray(secondArray)) {
      isEqual = firstArray.length == secondArray.length;
      if (isEqual) {
        var i = 0;
        firstArray.forEach(function(element) {
          if (isEqual){
            isEqual = isEqualElements(element, secondArray[i++]);
          }
        })
      }
    }

    return isEqual;
  };

  var isEqualObjects = function(firstObject, secondObject) {
    var isEqual;
    var checkedProperties = [];
    if (typeof firstObject == 'object' && typeof secondObject == 'object') {
      isEqual = true;
      for(var property in firstObject) {
        if (isEqual) {
          checkedProperties.push(property);
          isEqual = isEqualElements(firstObject[property], secondObject[property]);
        }
      }
      if (isEqual) {
        for(var property in secondObject) {
          if (isEqual) {
            if (checkedProperties.indexOf(property) == -1) {
              isEqual = false;
            }
          }
        }
      }
    }

    return isEqual;
  }

  var isEqual;
  if (typeof firstElement == 'object' && typeof secondElement == 'object') {
    if (Array.isArray(firstElement) && Array.isArray(secondElement)) {
      isEqual = isEqualArrays(firstElement, secondElement);
    } else{
      if (Array.isArray(firstElement) || Array.isArray(secondElement)) {
        isEqual = false;
      } else {
        isEqual = isEqualObjects(firstElement, secondElement);
      }
    }
  } else {
    isEqual = firstElement == secondElement;
  }

  return isEqual;
}

exports.startInspection = function() {
  startCheckingIndexes();
}<|endoftext|>


<commit_before>import fs from 'fs';
import path from 'path';
import Mocha from 'mocha';
import chai from 'chai';
import chaiHttp from 'chai-http';
import { stringify } from 'flatted/cjs';

import config from './src/config';
import api from './src/server';
import logger from './src/utils/logger';
import { dropDBs } from './test/utils';

api.use((err, req, res, next) => {
	if (err) {
		logger.error(err.stack);
		if (err.request) {
			logger.error(`REQUEST = ${stringify(err.request)}`);
		}
		if (err.response) {
			logger.error(`RESPONSE = ${stringify(err.response)}`);
		}
	}
	next(err, req, res);
});

chai.use(chaiHttp);

function wrapMocha(onPrepare, onUnprepare) {
	// Monkey-patch run method
	const run = Mocha.prototype.run;

	//XXX: using function syntax instead of fat-arrow syntax
	//     to avoid implicit binding of 'this'
	Mocha.prototype.run = function(done) {
		const self = this;
		onPrepare().then(() => {
			//XXX: ditto
			run.call(self, function() {
				if (typeof onUnprepare === 'function') {
					onUnprepare.apply(this, arguments);
				}
				done.apply(this, arguments);
			});
		}).catch(err => {
			if (err instanceof Error) {
				console.error(err.stack);
			}
			process.exit(1);
		});
	};
}

wrapMocha(async () => {
	if (!config.database.uri)
		throw new Error('Missing MongoDB connection string. Check config');
	if (!config.cache.uri)
		throw new Error('Missing Redis connection string. Check config');
	if (!config.database.uri.includes('localhost') && !config.database.uri.includes('127.0.0.1'))
		throw new Error('MongoDB connection string contains non-local address. For safety reasons test suite can only connect to local databases. Check config');
	if (!config.cache.uri.includes('localhost') && !config.cache.uri.includes('127.0.0.1'))
		throw new Error('Redis connection string contains non-local address. For safety reasons test suite can only connect to local databases. Check config');

	//XXX: drop all data before running tests
	await dropDBs();

	fs.readdirSync(path.join(__dirname, 'src', 'routes')).forEach(file => {
		if (file.endsWith('.js')) {
			require(`./src/routes/${file}`)(api);
		}
	});
}, failures => {
	//XXX: it seems Travis-ci is having trouble with process wrap-up procedures so lets
	//     allocate more time before shutting down
	const timeout = process.env.TRAVIS ? 10000 : 1500;
	//XXX: don't care about open connections
	setTimeout(() => process.exit(failures ? 1 : 0), 1500);
});
<commit_msg>Print out termination time<commit_after>import fs from 'fs';
import path from 'path';
import Mocha from 'mocha';
import chai from 'chai';
import chaiHttp from 'chai-http';
import { stringify } from 'flatted/cjs';

import config from './src/config';
import api from './src/server';
import logger from './src/utils/logger';
import { dropDBs } from './test/utils';

api.use((err, req, res, next) => {
	if (err) {
		logger.error(err.stack);
		if (err.request) {
			logger.error(`REQUEST = ${stringify(err.request)}`);
		}
		if (err.response) {
			logger.error(`RESPONSE = ${stringify(err.response)}`);
		}
	}
	next(err, req, res);
});

chai.use(chaiHttp);

function wrapMocha(onPrepare, onUnprepare) {
	// Monkey-patch run method
	const run = Mocha.prototype.run;

	//XXX: using function syntax instead of fat-arrow syntax
	//     to avoid implicit binding of 'this'
	Mocha.prototype.run = function(done) {
		const self = this;
		onPrepare().then(() => {
			//XXX: ditto
			run.call(self, function() {
				if (typeof onUnprepare === 'function') {
					onUnprepare.apply(this, arguments);
				}
				done.apply(this, arguments);
			});
		}).catch(err => {
			if (err instanceof Error) {
				console.error(err.stack);
			}
			process.exit(1);
		});
	};
}

wrapMocha(async () => {
	if (!config.database.uri)
		throw new Error('Missing MongoDB connection string. Check config');
	if (!config.cache.uri)
		throw new Error('Missing Redis connection string. Check config');
	if (!config.database.uri.includes('localhost') && !config.database.uri.includes('127.0.0.1'))
		throw new Error('MongoDB connection string contains non-local address. For safety reasons test suite can only connect to local databases. Check config');
	if (!config.cache.uri.includes('localhost') && !config.cache.uri.includes('127.0.0.1'))
		throw new Error('Redis connection string contains non-local address. For safety reasons test suite can only connect to local databases. Check config');

	//XXX: drop all data before running tests
	await dropDBs();

	fs.readdirSync(path.join(__dirname, 'src', 'routes')).forEach(file => {
		if (file.endsWith('.js')) {
			require(`./src/routes/${file}`)(api);
		}
	});
}, failures => {
	//XXX: it seems Travis-ci is having trouble with process wrap-up procedures so lets
	//     allocate more time before shutting down
	const timeout = process.env.TRAVIS ? 10000 : 1500;
	logger.info(`Terminating in ${timeout / 1000} seconds`);
	//XXX: don't care about open connections
	setTimeout(() => process.exit(failures ? 1 : 0), timeout);
});
<|endoftext|>


<commit_before>#!/usr/bin/env node

var git = require('git-rev');
var chalk = require('chalk');
var exec = require('exec');

var error = chalk.bold.red;
var success = chalk.bold.green;

///////////////////////////////////////////////////////////
function log(msg) {
  console.log(success(msg));
}

///////////////////////////////////////////////////////////
function err(msg) {
  log(error(msg));
}

///////////////////////////////////////////////////////////
function addAllToGit(msg) {
  exec('git add --all', function(error, out, code) {
      if (err instanceof Error) {
        err(error);
        return false;
      } else {
        log("Successfully added all.");
        commitWithMessage(msg);
      }
  });
}

///////////////////////////////////////////////////////////
function commitWithMessage(msg) {
  var messageString = 'git commit -m "' + msg + '"';
  exec(messageString, function(error, out, code) {
      if (err instanceof Error) {
        err(error);
        return false;
      } else {
        log("Committing with message: " + msg);
        pushToCurrentBranch();
      }
  });
}

///////////////////////////////////////////////////////////
function pushToCurrentBranch() {
    git.branch(function (str) {
      exec('git push origin ' + str, function(error, out, code) {
        if (err instanceof Error) {
          err(error);
          return false;
        } else {
          log(error);
        }
      });
  });
}

///////////////////////////////////////////////////////////
function main() {
  var msg = process.argv.slice(2);
  if (!msg || msg == null) {
    err('You must include a commit message');
    return;
  }
  addAllToGit(msg);
}

module.exports.main = main;

<commit_msg>Adding length check<commit_after>#!/usr/bin/env node

var git = require('git-rev');
var chalk = require('chalk');
var exec = require('exec');

var error = chalk.bold.red;
var success = chalk.bold.green;

///////////////////////////////////////////////////////////
function log(msg) {
  console.log(success(msg));
}

///////////////////////////////////////////////////////////
function err(msg) {
  log(error(msg));
}

///////////////////////////////////////////////////////////
function addAllToGit(msg) {
  exec('git add --all', function(error, out, code) {
      if (err instanceof Error) {
        err(error);
        return false;
      } else {
        log("Successfully added all.");
        commitWithMessage(msg);
      }
  });
}

///////////////////////////////////////////////////////////
function commitWithMessage(msg) {
  var messageString = 'git commit -m "' + msg + '"';

  exec(messageString, function(error, out, code) {
      if (err instanceof Error) {
        err(error);
        return false;
      } else {
        log("Committing with message: " + msg);
        pushToCurrentBranch();
      }
  });
}

///////////////////////////////////////////////////////////
function pushToCurrentBranch() {
    git.branch(function (str) {
      exec('git push origin ' + str, function(error, out, code) {
        if (err instanceof Error) {
          err(error);
          return false;
        } else {
          log(error);
        }
      });
  });
}

///////////////////////////////////////////////////////////
function main() {
  var msg = process.argv.slice(2);
  if (!msg || (msg + "").trim().length == 0) {
    err('You must include a commit message');
    return;
  }
  addAllToGit(msg);
}

module.exports.main = main;

<|endoftext|>


<commit_before>// Copyright 2008 The Closure Library Authors. All Rights Reserved.
//
// 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.

/**
 * @fileoverview The module loader for loading modules across the network.
 *
 * Webkit and IE do not guarantee that scripts appended to the document
 * are executed in the order they are added. For production mode, we use
 * XHRs to load scripts, because they do not have this problem and they
 * have superior mechanisms for handling failure. However, XHR-evaled
 * scripts are harder to debug.
 *
 * In debugging mode, we use normal script tags. In order to make this work
 * in WebKit and IE, we load the scripts in serial: we do not execute
 * script B to the document until we are certain that script A is
 * finished loading.
 *
 */

goog.provide('goog.module.ModuleLoader');

goog.require('goog.array');
goog.require('goog.debug.Logger');
goog.require('goog.dom');
goog.require('goog.events.EventHandler');
goog.require('goog.module.BaseModuleLoader');
goog.require('goog.net.BulkLoader');
goog.require('goog.net.EventType');
goog.require('goog.net.jsloader');

/**
 * A class that loads Javascript modules.
 * @constructor
 * @extends {goog.module.BaseModuleLoader}
 */
goog.module.ModuleLoader = function() {
  goog.module.BaseModuleLoader.call(this);

  /**
   * Event handler for managing handling events.
   * @type {goog.events.EventHandler}
   * @private
   */
  this.eventHandler_ = new goog.events.EventHandler(this);
};
goog.inherits(goog.module.ModuleLoader, goog.module.BaseModuleLoader);

/**
 * A logger.
 * @type {goog.debug.Logger}
 * @protected
 */
goog.module.ModuleLoader.prototype.logger = goog.debug.Logger.getLogger(
    'goog.module.ModuleLoader');

/** @override */
goog.module.ModuleLoader.prototype.loadModulesInternal = function(
    ids, moduleInfoMap, opt_successFn, opt_errorFn, opt_timeoutFn,
    opt_forceReload) {
  var uris = [];
  for (var i = 0; i < ids.length; i++) {
    goog.array.extend(uris, moduleInfoMap[ids[i]].getUris());
  }
  this.logger.info('loadModules ids:' + ids + ' uris:' + uris);

  if (this.getDebugMode()) {
    // In debug mode use <script> tags rather than XHRs to load the files.
    // This makes it possible to debug and inspect stack traces more easily.
    // It's also possible to use it to load JavaScript files that are hosted on
    // another domain.
    goog.net.jsloader.loadMany(uris);
  } else {
    var bulkLoader = new goog.net.BulkLoader(uris);
    var eventHandler = this.eventHandler_;
    eventHandler.listen(
        bulkLoader,
        goog.net.EventType.SUCCESS,
        goog.bind(this.handleSuccess, this, bulkLoader, ids,
            opt_successFn, opt_errorFn),
        false,
        null);
    eventHandler.listen(
        bulkLoader,
        goog.net.EventType.ERROR,
        goog.bind(this.handleError, this, bulkLoader, ids, opt_errorFn),
        false,
        null);
    // TODO(user): Need to handle timeouts in the module loading code.

    bulkLoader.load();
  }
};

/**
 * Create a script tag.
 * @param {string} uri The uri of the script.
 * @return {Element} The new tag.
 * @private
 */
goog.module.ModuleLoader.prototype.createScriptElement_ = function(uri) {
  var scriptEl = goog.dom.createElement('script');
  scriptEl.src = uri;
  scriptEl.type = 'text/javascript';
  return scriptEl;
};

/**
 * Handles a successful response to a request for one or more modules.
 *
 * @param {goog.net.BulkLoader} bulkLoader The bulk loader.
 * @param {Array.<string>} moduleIds The ids of the modules requested.
 * @param {function()} successFn The callback for success.
 * @param {function(?number)} errorFn The callback for error.
 */
goog.module.ModuleLoader.prototype.handleSuccess = function(
    bulkLoader, moduleIds, successFn, errorFn) {
  var jsCode = bulkLoader.getResponseTexts().join('\n');

  this.handleRequestSuccess(jsCode, moduleIds, successFn, errorFn);

  // NOTE: A bulk loader instance is used for loading a set of module ids. Once
  // these modules have been loaded succesfully or in error the bulk loader
  // should be disposed as it is not needed anymore. A new bulk loader is
  // instantiated for any new modules to be loaded. The dispose is called
  // on a timer so that the bulkloader has a chance to release its
  // objects.
  goog.Timer.callOnce(bulkLoader.dispose, 5, bulkLoader);
};

/**
 * Handles an error during a request for one or more modules.
 * @param {goog.net.BulkLoader} bulkLoader The bulk loader.
 * @param {Array.<string>} moduleIds The ids of the modules requested.
 * @param {function(?number)} errorFn The function to call on failure.
 * @param {number} status The response status.
 */
goog.module.ModuleLoader.prototype.handleError = function(
    bulkLoader, moduleIds, errorFn, status) {
  this.handleRequestError(moduleIds, errorFn, status);

  // NOTE: A bulk loader instance is used for loading a set of module ids. Once
  // these modules have been loaded succesfully or in error the bulk loader
  // should be disposed as it is not needed anymore. A new bulk loader is
  // instantiated for any new modules to be loaded. The dispose is called
  // on another thread so that the bulkloader has a chance to release its
  // objects.
  goog.Timer.callOnce(bulkLoader.dispose, 5, bulkLoader);
};

/** @override */
goog.module.ModuleLoader.prototype.disposeInternal = function() {
  goog.module.ModuleLoader.superClass_.disposeInternal.call(this);

  this.eventHandler_.dispose();
  this.eventHandler_ = null;
};
<commit_msg><commit_after>// Copyright 2008 The Closure Library Authors. All Rights Reserved.
//
// 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.

/**
 * @fileoverview The module loader for loading modules across the network.
 *
 * Webkit and IE do not guarantee that scripts appended to the document
 * are executed in the order they are added. For production mode, we use
 * XHRs to load scripts, because they do not have this problem and they
 * have superior mechanisms for handling failure. However, XHR-evaled
 * scripts are harder to debug.
 *
 * In debugging mode, we use normal script tags. In order to make this work
 * in WebKit and IE, we load the scripts in serial: we do not execute
 * script B to the document until we are certain that script A is
 * finished loading.
 *
 */

goog.provide('goog.module.ModuleLoader');

goog.require('goog.array');
goog.require('goog.debug.Logger');
goog.require('goog.dom');
goog.require('goog.events.EventHandler');
goog.require('goog.module.BaseModuleLoader');
goog.require('goog.net.BulkLoader');
goog.require('goog.net.EventType');
goog.require('goog.net.jsloader');

/**
 * A class that loads Javascript modules.
 * @constructor
 * @extends {goog.module.BaseModuleLoader}
 */
goog.module.ModuleLoader = function() {
  goog.module.BaseModuleLoader.call(this);

  /**
   * Event handler for managing handling events.
   * @type {goog.events.EventHandler}
   * @private
   */
  this.eventHandler_ = new goog.events.EventHandler(this);
};
goog.inherits(goog.module.ModuleLoader, goog.module.BaseModuleLoader);

/**
 * A logger.
 * @type {goog.debug.Logger}
 * @protected
 */
goog.module.ModuleLoader.prototype.logger = goog.debug.Logger.getLogger(
    'goog.module.ModuleLoader');

/** @override */
goog.module.ModuleLoader.prototype.loadModulesInternal = function(
    ids, moduleInfoMap, opt_successFn, opt_errorFn, opt_timeoutFn,
    opt_forceReload) {
  var uris = [];
  for (var i = 0; i < ids.length; i++) {
    goog.array.extend(uris, moduleInfoMap[ids[i]].getUris());
  }
  this.logger.info('loadModules ids:' + ids + ' uris:' + uris);

  if (this.getDebugMode()) {
    // In debug mode use <script> tags rather than XHRs to load the files.
    // This makes it possible to debug and inspect stack traces more easily.
    // It's also possible to use it to load JavaScript files that are hosted on
    // another domain.
    goog.net.jsloader.loadMany(uris);
  } else {
    var bulkLoader = new goog.net.BulkLoader(uris);
    var eventHandler = this.eventHandler_;
    eventHandler.listen(
        bulkLoader,
        goog.net.EventType.SUCCESS,
        goog.bind(this.handleSuccess, this, bulkLoader, ids,
            opt_successFn, opt_errorFn),
        false,
        null);
    eventHandler.listen(
        bulkLoader,
        goog.net.EventType.ERROR,
        goog.bind(this.handleError, this, bulkLoader, ids, opt_errorFn),
        false,
        null);
    // TODO(user): Need to handle timeouts in the module loading code.

    bulkLoader.load();
  }
};

/**
 * Handles a successful response to a request for one or more modules.
 *
 * @param {goog.net.BulkLoader} bulkLoader The bulk loader.
 * @param {Array.<string>} moduleIds The ids of the modules requested.
 * @param {function()} successFn The callback for success.
 * @param {function(?number)} errorFn The callback for error.
 */
goog.module.ModuleLoader.prototype.handleSuccess = function(
    bulkLoader, moduleIds, successFn, errorFn) {
  var jsCode = bulkLoader.getResponseTexts().join('\n');

  this.handleRequestSuccess(jsCode, moduleIds, successFn, errorFn);

  // NOTE: A bulk loader instance is used for loading a set of module ids. Once
  // these modules have been loaded succesfully or in error the bulk loader
  // should be disposed as it is not needed anymore. A new bulk loader is
  // instantiated for any new modules to be loaded. The dispose is called
  // on a timer so that the bulkloader has a chance to release its
  // objects.
  goog.Timer.callOnce(bulkLoader.dispose, 5, bulkLoader);
};

/**
 * Handles an error during a request for one or more modules.
 * @param {goog.net.BulkLoader} bulkLoader The bulk loader.
 * @param {Array.<string>} moduleIds The ids of the modules requested.
 * @param {function(?number)} errorFn The function to call on failure.
 * @param {number} status The response status.
 */
goog.module.ModuleLoader.prototype.handleError = function(
    bulkLoader, moduleIds, errorFn, status) {
  this.handleRequestError(moduleIds, errorFn, status);

  // NOTE: A bulk loader instance is used for loading a set of module ids. Once
  // these modules have been loaded succesfully or in error the bulk loader
  // should be disposed as it is not needed anymore. A new bulk loader is
  // instantiated for any new modules to be loaded. The dispose is called
  // on another thread so that the bulkloader has a chance to release its
  // objects.
  goog.Timer.callOnce(bulkLoader.dispose, 5, bulkLoader);
};

/** @override */
goog.module.ModuleLoader.prototype.disposeInternal = function() {
  goog.module.ModuleLoader.superClass_.disposeInternal.call(this);

  this.eventHandler_.dispose();
  this.eventHandler_ = null;
};
<|endoftext|>


<commit_before>// the document ready that launches everything.

var ready = function(){

  console.log('working!');
  sortByRatings();
  displayAllOutfits();
  displayRecentOutfits();
  displayTrendingHashtags();
  newOutfit();
  bindEvents();
}
// FIND A BETTER WAY TO TRIGGER THIS SO IT DOESN'T CAUSE EVERYTHING TO REFRESH WHEN YOU DO AN AJAX CALL
$(document).ready(ready);
$(document).on('page:load', ready)

function bindEvents(){
  $('.img-thumbnail').on('click', function(event) {
    var imgURL = this.src
    selectInstagramImage(imgURL);
  });
  $('#get_from_instagram').on('click', function(event) {
    event.preventDefault();
    $.ajax({
      url: '/instagram/recent',
      type: 'GET',
      dataType: 'html',
    })
    .done(function(response) {
      $('#instagram_select').html(response)
    });
  });
  $('#search-form').on('submit', function(event){
    event.preventDefault();
    displaySearchedOutfits();
  })

};

//Instagram functions
function selectInstagramImage(imgURL){
  $('#outfit_image_url').val(imgURL);
  $('#newoutfitthumbnail').append("")
  $('#instagram_select').empty();
};

// STAR RATINGS RAN HERE
// When you search for something it displays all outfits that correllate with hashtag
function displaySearchedOutfits(event) {
  var source = $("#all-outfits-template").html();
  var template =Handlebars.compile(source);
  var context = {}

  $.ajax({
    url: '/search',
    data: {hashtag: $('#search-box')[0].value},

  })
  .done(function(data) {
    context = {allOutfits: data};
    $('#all-outfits').html(template(context));
    addAverageRating(data);
    addRatingListener(); //function to add star ratings and allow to give star rating
    newRatingStarsClick();
  })
}

// SETS AVERAGE RATING FOR EACH OUTFIT ON FEED. DATA COMES FROM WHATEVER AJAX CALL POPULATES THE FEED.
function addAverageRating(data) {
 for (var i = 0; i < data.length ; i++ ) {
  var rating = data[i].avg_rating
  if (rating > 0) {
    $("#rating-" + i + " div:lt("+ rating +")").css('background', "url('../star-full.png')")
  }
}
}

// Also Calls the Star Ratings because it displays all outfits
// SEE IF WE CAN MOVE ALL FUNCTIONS TO A RENDER FUNCTION SO IT DOESN'T HAVE TO CALL EVERYTHING
function displayAllOutfits(){
  var source = $("#all-outfits-template").html();
  var template =Handlebars.compile(source);
  var context = {}

  $.ajax({
    url: "/ensembles"
  }).done(function(data){
    context = {allOutfits: data};
    $('#all-outfits').append(template(context));
    addAverageRating(data);
    addRatingListener();
    newRatingStarsClick();
    sortByRatings();
  })
}

// IN PROGRESS. CURRENTLY RETURNS AN ARRAY SORTED HIGHEST TO LOWEST WITHOUT CORRESPONDING VALUES
function sortByRatings() {
  $('#sort-by-ratings').on('click', function() {
    var allRatings = $(".rating");
    console.log(allRatings)
    var sortedOutfits = allRatings.sort(function(a,b){
      return a.getAttribute('value') - b.getAttribute('value')
    })
    console.log(sortedOutfits)

    // ratingsToSort = []
    // var context = {}
    // console.log(allRatings);
    // for (var i=0; i < allRatings.length; i++) {
      // ratingsToSort.push(allRatings[i].getAttribute('value'));
      // console.log(sortByRatings);
    // }
      // console.log(ratingsToSort);
      // console.log(ratingsToSort.sort(function(a, b){return b-a}));

    // var sortedOutfits = source.sort(function(a,b){
    //   return a-b
  })

    // context = {allOutfits: sortedOutfits};
    // $('#all-outfits').html(template(context));

  // })
}
// WAITS FOR RATING BUTTON TO BE CLICKED
// SEE IF ALL LISTENERS CAN BE MOVED TO LISTENER MODULE
function addRatingListener() {
  $('.rate-this-button').on('click', function(event) {
    $(this).next('.rating-form').css('display', 'block');

  })
}

// POPULATES A HIDDEN VALUE IN FORM THAT WILL LATER UPDATE AR IN POST ROUTE.
function newRatingStarsClick(){
  $('.new-rating-stars').on('click', function(event){
    console.log('clicked on a star')
    var starNumber = event.currentTarget.id.substring(4)
    var thisOutfitsRatingForm = $(this).parent()[0]
    var outfitIndex = thisOutfitsRatingForm.id.substring(10)
    $("#newrating-" + outfitIndex + " div:lt("+ starNumber +")").css('background', "url('../star-full.png')")
    $("#form-" + outfitIndex)[0][0].value = starNumber
  })
}
// SELF EXPLANATORY. ANYTHING THAT JUST GOT ADDED GETS PUT TO THE TOP OF THE FEED.
// THIS DISPLAYS ON THE WIDGET ON THE LEFT
function displayRecentOutfits (){
  var source = $("#recent-outfits-template").html();
  var template =Handlebars.compile(source);
  var context = {};

  $.ajax({
    url: window.location.pathname + "/ensembles"
  }).done(function(data){
    context = {recentOutfits: data};
    $('#recent-outfits').html(template(context));
  })
}

// THE WIDGET THAT DISPLAYS ALL HASHTAGS ON THE RIGHT SIDE OF THE SCREEN. RENAME TO WIDGET SOON.
function displayTrendingHashtags (){
  var source = $("#trending-hashtags-template").html();
  var template = Handlebars.compile(source);
  var context = {};

  $.ajax({
    url: "/hashtags"
  }).done(function(data){
    context = {trendingHashtags: data};
    $('#trending-hashtags').html(template(context));
    $('.hashtag-link').on('click', function(event){
      event.preventDefault();

      displayHashtagOutfits(event);
    })
  })
}

// THIS IS THE SAME AS DISPLAY ALL OUTFITS AND WE CAN PROBABLY BURN IT.
function displayHashtagOutfits(event) {
  var source = $("#all-outfits-template").html();
  var template =Handlebars.compile(source);
  var context = {}

  $.ajax({
    url: event.currentTarget.href,
  })
  .done(function(data) {
    context = {allOutfits: data};
    $('#all-outfits').html(template(context));
    addAverageRating(data);
    addRatingListener();
    newRatingStarsClick();
  })
}

// POST ROUTE THAT ENABLES CLOUDINARY AND PREPENDS PICTURE AND DATA TO TOP OF FEED
function newOutfit() {
  $('#newoutfit').on("click", function(event){
    console.log('clicked!');
    event.preventDefault();
    $.ajax({
      url: window.location.pathname+'/ensembles/new',
      type: 'GET',
      dataType: 'HTML',
      // data: {param1: 'value1'},
    })
    .done(function(a) {
      console.log("success");
      $('#all-outfits').prepend(a);
      uploadImage();
    })
    .fail(function() {
      console.log("error");
    })
    .always(function() {
      console.log("complete");
    });

  });
}
// MOSTLY VANILLA JS TO BRING UP CLOUDINARY WIDGET. RENAME MAGIC SOON.
var magic = null
function uploadImage() {
 document.getElementById("upload_widget_opener").addEventListener("click", function() {

  cloudinary.openUploadWidget({ cloud_name: 'dzxyyevk0', upload_preset: 'iiv6os2n', max_files: 1, cropping_aspect_ratio: 1, },
    function(error, result) { console.log(error, result)
      magic = result;
      console.log('still working');
      console.log(magic)
      var imgURL = magic[0].secure_url;
      $('#outfit_image_url').val(imgURL);

    });

}, false);

}

<commit_msg>refactored render out of displayalloutfits and made feed object constructor<commit_after>// the document ready that launches everything.

var ready = function(){

  console.log('working!');
  displayAllOutfits();
  displayRecentOutfits();
  displayTrendingHashtags();
  newOutfit();
  bindEvents();
  // sortByRatings();
}
// FIND A BETTER WAY TO TRIGGER THIS SO IT DOESN'T CAUSE EVERYTHING TO REFRESH WHEN YOU DO AN AJAX CALL
$(document).ready(ready);
$(document).on('page:load', ready)

function bindEvents(){
  $('.img-thumbnail').on('click', function(event) {
    var imgURL = this.src
    selectInstagramImage(imgURL);
  });
  $('#get_from_instagram').on('click', function(event) {
    event.preventDefault();
    $.ajax({
      url: '/instagram/recent',
      type: 'GET',
      dataType: 'html',
    })
    .done(function(response) {
      $('#instagram_select').html(response)
    });
  });
  $('#search-form').on('submit', function(event){
    event.preventDefault();
    displaySearchedOutfits();
  })

};

//Instagram functions
function selectInstagramImage(imgURL){
  $('#outfit_image_url').val(imgURL);
  $('#newoutfitthumbnail').append("")
  $('#instagram_select').empty();
};

// STAR RATINGS RAN HERE
// When you search for something it displays all outfits that correllate with hashtag
function displaySearchedOutfits(event) {
  var source = $("#all-outfits-template").html();
  var template =Handlebars.compile(source);
  var context = {}

  $.ajax({
    url: '/search',
    data: {hashtag: $('#search-box')[0].value},

  })
  .done(function(data) {
    context = {allOutfits: data};
    $('#all-outfits').html(template(context));
    addAverageRating(data);
    addRatingListener(); //function to add star ratings and allow to give star rating
    newRatingStarsClick();
  })
}

// SETS AVERAGE RATING FOR EACH OUTFIT ON FEED. DATA COMES FROM WHATEVER AJAX CALL POPULATES THE FEED.
function addAverageRating(data) {
 for (var i = 0; i < data.length ; i++ ) {
  var rating = data[i].avg_rating
  if (rating > 0) {
    $("#rating-" + i + " div:lt("+ rating +")").css('background', "url('../star-full.png')")
  }
}
}

// Also Calls the Star Ratings because it displays all outfits
// SEE IF WE CAN MOVE ALL FUNCTIONS TO A RENDER FUNCTION SO IT DOESN'T HAVE TO CALL EVERYTHING
function displayAllOutfits(){
  $.ajax({
    url: "/ensembles"
  }).done(function(data){
    renderFeed(data);
  })
}

// IN PROGRESS. CURRENTLY RETURNS AN ARRAY SORTED HIGHEST TO LOWEST WITHOUT CORRESPONDING VALUES

// WAITS FOR RATING BUTTON TO BE CLICKED
// SEE IF ALL LISTENERS CAN BE MOVED TO LISTENER MODULE
function addRatingListener() {
  $('.rate-this-button').on('click', function(event) {
    $(this).next('.rating-form').css('display', 'block');

  })
}

// POPULATES A HIDDEN VALUE IN FORM THAT WILL LATER UPDATE AR IN POST ROUTE.
function newRatingStarsClick(){
  $('.new-rating-stars').on('click', function(event){
    console.log('clicked on a star')
    var starNumber = event.currentTarget.id.substring(4)
    var thisOutfitsRatingForm = $(this).parent()[0]
    var outfitIndex = thisOutfitsRatingForm.id.substring(10)
    $("#newrating-" + outfitIndex + " div:lt("+ starNumber +")").css('background', "url('../star-full.png')")
    $("#form-" + outfitIndex)[0][0].value = starNumber
  })
}
// SELF EXPLANATORY. ANYTHING THAT JUST GOT ADDED GETS PUT TO THE TOP OF THE FEED.
// THIS DISPLAYS ON THE WIDGET ON THE LEFT
function displayRecentOutfits (){
  var source = $("#recent-outfits-template").html();
  var template =Handlebars.compile(source);
  var context = {};

  $.ajax({
    url: window.location.pathname + "/ensembles"
  }).done(function(data){
    context = {recentOutfits: data};
    $('#recent-outfits').html(template(context));
  })
}

// THE WIDGET THAT DISPLAYS ALL HASHTAGS ON THE RIGHT SIDE OF THE SCREEN. RENAME TO WIDGET SOON.
function displayTrendingHashtags (){
  var source = $("#trending-hashtags-template").html();
  var template = Handlebars.compile(source);
  var context = {};

  $.ajax({
    url: "/hashtags"
  }).done(function(data){
    context = {trendingHashtags: data};
    $('#trending-hashtags').html(template(context));
    $('.hashtag-link').on('click', function(event){
      event.preventDefault();

      displayHashtagOutfits(event);
    })
  })
}

// THIS IS THE SAME AS DISPLAY ALL OUTFITS AND WE CAN PROBABLY BURN IT.
function displayHashtagOutfits(event) {
  var source = $("#all-outfits-template").html();
  var template =Handlebars.compile(source);
  var context = {}

  $.ajax({
    url: event.currentTarget.href,
  })
  .done(function(data) {
    context = {allOutfits: data};
    $('#all-outfits').html(template(context));
    addAverageRating(data);
    addRatingListener();
    newRatingStarsClick();
  })
}

// POST ROUTE THAT ENABLES CLOUDINARY AND PREPENDS PICTURE AND DATA TO TOP OF FEED
function newOutfit() {
  $('#newoutfit').on("click", function(event){
    console.log('clicked!');
    event.preventDefault();
    $.ajax({
      url: window.location.pathname+'/ensembles/new',
      type: 'GET',
      dataType: 'HTML',
      // data: {param1: 'value1'},
    })
    .done(function(a) {
      console.log("success");
      $('#all-outfits').prepend(a);
      uploadImage();
    })
    .fail(function() {
      console.log("error");
    })
    .always(function() {
      console.log("complete");
    });

  });
}
// MOSTLY VANILLA JS TO BRING UP CLOUDINARY WIDGET. RENAME MAGIC SOON.
var magic = null
function uploadImage() {
 document.getElementById("upload_widget_opener").addEventListener("click", function() {

  cloudinary.openUploadWidget({ cloud_name: 'dzxyyevk0', upload_preset: 'iiv6os2n', max_files: 1, cropping_aspect_ratio: 1, },
    function(error, result) { console.log(error, result)
      magic = result;
      console.log('still working');
      console.log(magic)
      var imgURL = magic[0].secure_url;
      $('#outfit_image_url').val(imgURL);

    });

}, false);

}

// function sortByRatings() {
//   $('#sort-by-ratings').on('click', function() {
//     var allOutfits = $(".individual-outfit");
//     console.log(allOutfits);
//     var outfits = [];
//     var outfit = new Outfit();

//     console.log(allOutfits[0].children);
//     // outfit.image = allOutfits[0].firstElementChild.currentSrc
//     // outfit.title

//     // for (var i=0; i < allOutfits.length; i++) {

//     // };
//     // var sortedOutfits = allRatings.sort(function(a,b){
//     //   return a.getAttribute('value') - b.getAttribute('value')
//     // })
//     // console.log(sortedOutfits)

//     // ratingsToSort = []
//     // var context = {}
//     // console.log(allRatings);
//     // for (var i=0; i < allRatings.length; i++) {
//       // ratingsToSort.push(allRatings[i].getAttribute('value'));
//       // console.log(sortByRatings);
//     // }
//       // console.log(ratingsToSort);
//       // console.log(ratingsToSort.sort(function(a, b){return b-a}));

//     // var sortedOutfits = source.sort(function(a,b){
//     //   return a-b
//   })

//     // context = {allOutfits: sortedOutfits};
//     // $('#all-outfits').html(template(context));

//   // })
// }

function Outfit() {
  this.outfit_id= ""
  this.title= ""
  this.image= ""
  this.types= []
  this.avg_rating= 0
  this.caption= ""
  this.user= ""
}

function constructFeed(data){
  currentFeed = []
  for (var i=0; i < data.length; i++) {
    var outfit = new Outfit();
    outfit.outfit_id = data[i].outfit_id
    outfit.title= data[i].title
    outfit.image= data[i].image
    outfit.types= data[i].types
    outfit.avg_rating= data[i].avg_rating
    outfit.caption= data[i].caption
    outfit.user= data[i].user
    currentFeed.push(outfit)
  }
  console.log(currentFeed)
};

function renderFeed(data){
  var source = $("#all-outfits-template").html();
  var template =Handlebars.compile(source);
  var context = {}
  context = {allOutfits: data};
  $('#all-outfits').append(template(context));
  addAverageRating(data);
  addRatingListener();
  newRatingStarsClick();
  constructFeed(data);

};

<|endoftext|>


<commit_before>var s, ControlWidget =
{
  settings:
  {
    update_url: "http://" + location.host + "/state",
    root_elem: $("#control_form fieldset")
  },

  init: function()
  {
    console.log("init ControlWidget");
    s = this.settings;
  },

  update_ui_with_component: function(the_component)
  {
    list_obj = $( "
", {
      "class": "my-new-list"
    });

    // change component name
    $("#control_form legend").html(the_component.name);

    $.each(the_component.properties, function(key, prop)
    {
      ControlWidget.add_control_for_property(prop);

      tmp = $( "
",
      {
        html: prop.type+": "+ prop.name + ": " + prop.value
      });

      list_obj.append(tmp)
    });
    list_obj.appendTo( "body" );
  },

  get_state_and_update: function()
  {
    ControlWidget.set_loading(true);

    $.getJSON(s.update_url, function(data){
      ControlWidget.update_ui_with_component(data[0]);
      ControlWidget.set_loading(false);
    });
  },

  set_loading: function(the_bool)
  {
    //TODO: implement
  },

  add_control_for_property: function(the_property)
  {
    var input_elem = undefined;
    var stripped_name = the_property.name.trim().replace(/ /g,'_');

    var group = $( "
", {
      "class": "form-group"
    });

    var label = $( "", {
      "class": "col-md-4 control-label",
      "for": stripped_name,
      "html": the_property.name
    });

    group.append(label);

    input_elem = $( "<input/>", {
        "name": stripped_name,
        "type": "text",
        "class": "form-control input-md",
        "value": the_property.value
    });
    input_col = $("
").append(input_elem);

    switch(the_property.type)
    {
      case "string":
        console.log("adding: " + the_property.name);
        input_elem.attr("type", "text");

        break;

      case "int":
      case "uint":
      case "float":
      case "double":
        input_elem.attr("type", "number");
        break;

      case "bool":
        input_elem.attr("type", "checkbox");
        input_elem.removeAttr('value');
        input_elem.prop('checked', the_property.value);
        break;

      default:
        break;
    }

    if(input_elem != undefined)
    {
      // add change event
      input_elem.on("change", function(){
          console.log(input_elem.attr("name") + " changed");
      });

      group.append(input_col);
      s.root_elem.append(group);
    }
  }
};

$(document).ready(function(){
  ControlWidget.init();
  ControlWidget.get_state_and_update();
});
<commit_msg>progress with inputs<commit_after>var s, ControlWidget =
{
  settings:
  {
    update_url: "http://" + location.host + "/state",
    root_elem: $("#control_form fieldset")
  },

  init: function()
  {
    console.log("init ControlWidget");
    s = this.settings;
  },

  update_ui_with_component: function(the_component)
  {
    // change component name
    $("#control_form legend").html(the_component.name);

    $.each(the_component.properties, function(key, prop)
    {
      ControlWidget.add_control_for_property(prop);
    });
  },

  get_state_and_update: function()
  {
    ControlWidget.set_loading(true);

    $.getJSON(s.update_url, function(data){
      ControlWidget.update_ui_with_component(data[0]);
      ControlWidget.set_loading(false);
    });
  },

  set_loading: function(the_bool)
  {
    //TODO: implement
  },

  add_control_for_property: function(the_property)
  {
    var input_elem = undefined;
    var stripped_name = the_property.name.trim().replace(/ /g,'_');

    var group = $( "
", {
      "class": "form-group"
    });

    var label = $( "", {
      "class": "col-md-4 control-label",
      "for": stripped_name,
      "html": the_property.name
    });

    group.append(label);

    input_elem = $( "<input/>", {
        "name": stripped_name,
        "type": "text",
        "class": "form-control input-md",
        "value": the_property.value
    });
    input_col = $("
").append(input_elem);

    switch(the_property.type)
    {
      case "string":
        input_elem.attr("type", "text");
        break;

      case "int":
      case "uint":
      case "float":
      case "double":
        input_elem.attr("type", "number");
        break;

      case "bool":
        input_elem.attr("type", "checkbox");
        input_elem.removeAttr('value');
        input_elem.prop('checked', the_property.value);
        break;

      case "vec4":
        input_elem.attr("type", "color");
        break;

      default:
        break;
    }

    if(input_elem != undefined)
    {
      // add change event
      input_elem.on("change", function(){
          console.log(input_elem.attr("name") + " changed");
      });

      group.append(input_col);
      s.root_elem.append(group);
    }
  }
};

$(document).ready(function(){
  ControlWidget.init();
  ControlWidget.get_state_and_update();
});
<|endoftext|>


<commit_before>var diagram_types = ['balances', 'rewards', 'costs'];
var cached_data = {};

// READY
function manager_balances_ready() {
    initialize_balance_diagrams();
    initialize_balance_diagrams_filters();

    resize_diagrams();
}

$(window).resize(function() {
    if (get_current_page() == 'balances') {
        resize_diagrams();
    }
});

function resize_diagrams() {
    // resize charts in tabs
    $.each(diagram_types, function(index, type) {
        var container = $('#' + type + '_container');
        var chart = container.highcharts();
        chart.setSize(container.parent().width(), container.parent().height(), false);
    });
}

function initialize_balance_diagrams() {
    $.each(diagram_types, function(index, type) {
        $('#' + type + '_container').highcharts({
            chart: {
                zoomType: 'xy'
            },
            title: {
                text: ''
            },
            xAxis: {
                categories: get_text('months')
            },
            yAxis: [{
                labels: {
                    format: '{value} €',
                    style: { color: Highcharts.getOptions().colors[1] }
                },
                title: {
                    text: 'Balances in €',
                    style: { color: Highcharts.getOptions().colors[1] }
                },
            }],
            plotOptions: {
                series: {
                    cursor: 'pointer',
                    point: {
                        events: {
                            click: function (e) {
                                $('#notice_container').empty();
                                var month = get_text('months').indexOf(e.currentTarget.category);
                                var year = get_year_from_string(this.series.name);
                                show_month_details(year, month);
                            }
                        }
                    },
                    marker: {
                        lineWidth: 1
                    }
                }
            },
            tooltip: {
                valueDecimals: 2
            },
            series: [],
            credits: {
                enabled: false
            }
        });
    });
}

function initialize_balance_diagrams_filters() {
    $.getJSON(api_base_url + 'history/', function(history_data) {
        $.each(history_data, function(index, year) {
            $('#diagram_filters').append(
                '\
                <input class="btn diagram_filter" type="checkbox" value="' + year + '">\
                ' + year + '');
        });
        $('.diagram_filter').change(function () {

            charts = [];
            $.each(diagram_types, function(index, type) {
                charts.push($('#' + type + '_container').highcharts());
            });
            var year = parseInt($(this).val());
            if ($(this).is(":checked")) {
                var found = false;
                $.each(charts, function(index, chart) {
                    $.each(chart.series, function(index2, series) {
                        if (series['name'].substr(series['name'].length - 4) == year) {
                            series.show(false);
                            found = true;
                        }
                    });
                });
                if (!found) {
                    $.getJSON(api_base_url + "balance/total/" + year + "/", function(data) {
                        cached_data[year] = data;
                        var balances = {
                            name: 'Total Balances in ' + year,
                            type: 'column',
                            data: []
                        };
                        var rewards = {
                            name: 'Total Rewards in ' + year,
                            type: 'column',
                            data: []
                        };
                        var costs = {
                            name: 'Total Costs in ' + year,
                            type: 'column',
                            data: [],
                        };
                        $.each(data, function(index, monthly_data) {
                            balances['data'].push(monthly_data.balance);
                            rewards['data'].push(monthly_data.rewards);
                            costs['data'].push(monthly_data.costs);
                        });
                        charts[0].addSeries(balances);
                        charts[1].addSeries(rewards);
                        charts[2].addSeries(costs);

                        // preselect tables details
                        if ($('#details_container').is(':empty')) {
                            show_month_details(year, data.length - 1);
                        } else {
                            update_date_selection();
                        }
                    });
                }
            } else {
                $.each(charts, function(index, chart) {
                    $.each(chart.series, function(index, series) {
                        if (get_year_from_string(series['name']) == year) {
                            series.hide(false);
                        }
                    });
                });
            }

            // if all series are unchecked, show all
            var all_unchecked = true;
            $(".diagram_filter").each(function() {
                if ($(this).is(":checked")) {
                    all_unchecked = false;
                }
            });
            if (all_unchecked) {
                $.each(charts, function(index, chart) {
                    $.each(chart.series, function(index, series) {
                        series.setVisible(true, false);
                    });
                });
            }

            // finally redraw all charts
            $.each(charts, function(index, chart) {
                chart.redraw();
            });
        });

        // preselect first filter
        $('.diagram_filter').first().parent().button('toggle');
    });
}

function show_month_details(year, month) {
    $.each(cached_data[year], function(index, monthly_data) {
        if (month == index) {
            update_balances_table(monthly_data, year, month);
            $('#selected_year').val(year);
            $('#selected_month').val(month);
        }
    });
}

function update_balances_table(data, year, month) {
    $.get('templates/balances_table.html', function(template) {
        var rendered = Mustache.render(template, {
            title: $.format.date(new Date(year, month, 1), "MMMM yyyy"),
            thermal_revenues: {
                text: get_text('thermal_revenues'),
                price: data['prices']['thermal_revenues'],
                value: data['kwh']['thermal_consumption'],
                total: Math.round(data['kwh']['thermal_consumption'] * data['prices']['thermal_revenues'] * 100)/100
            },
            warmwater_revenues: {
                text: get_text('warmwater_revenues'),
                price: data['prices']['warmwater_revenues'],
                value: data['kwh']['warmwater_consumption'],
                total: Math.round(data['kwh']['warmwater_consumption'] * data['prices']['warmwater_revenues'] * 100)/100
            },
            electrical_revenues: {
                text: get_text('electrical_revenues'),
                price: data['prices']['electrical_revenues'],
                value: data['kwh']['electrical_consumption'],
                total: Math.round(data['kwh']['electrical_consumption'] * data['prices']['electrical_revenues'] * 100)/100
            },
            electrical_infeed: {
                text: get_text('electrical_infeed'),
                price: data['prices']['feed_in_reward'] ,
                value: data['kwh']['electrical_infeed'],
                total: Math.round(data['kwh']['electrical_infeed'] * data['prices']['feed_in_reward'] * 100)/100
            },
            gas_consumption: {
                text: get_text('gas_consumption'),
                price: data['prices']['gas_costs'],
                value: data['kwh']['gas_consumption'],
                total: Math.round(data['kwh']['gas_consumption'] * data['prices']['gas_costs'] * 100)/100
            },
            electrical_purchase: {
                text: get_text('electrical_purchase'),
                price: data['prices']['electrical_costs'],
                value: data['kwh']['electrical_purchase'],
                total: Math.round(data['kwh']['electrical_purchase'] * data['prices']['electrical_costs'] * 100)/100
            },
            rewards: data['rewards'],
            costs: data['costs'],
            balance: data['balance'],
        });
        $('#details_container').html(rendered);
    }).done(function() {
        $('#export_button').click(function(event) {
            event.preventDefault();
            export_table($('#table_container'));
        });

        update_date_selection(year, month);
    });
}

function update_date_selection(selected_year, selected_month) {
    var month_options = "";
    $.each(get_text('months'), function(index, month) {
        month_options += '<option value="' + index + '" ' + (index == selected_month ? ' selected': '') + '>' + month + '</option>';
    });
    $('#selected_month').html(month_options);

    $('#selected_month').change(function() {
        show_month_details($('#selected_year').val(), $(this).val());
    });

    var selected_year = $('#selected_year').val();
    var year_options = "";
    $.each(cached_data, function(year, data) {
        year_options += '<option' + (year == selected_year ? ' selected': '') + '>' + year + '</option>';
    });
    $('#selected_year').html(year_options);

    $('#selected_year').change(function() {
        show_month_details($(this).val(), $('#selected_month').val());
    });
}

function get_year_from_string(string) {
    return string.substr(string.length - 4);
}
<commit_msg>Date selection bugfix. Closes #284<commit_after>var diagram_types = ['balances', 'rewards', 'costs'];
var cached_data = {};

// READY
function manager_balances_ready() {
    initialize_balance_diagrams();
    initialize_balance_diagrams_filters();

    resize_diagrams();
}

$(window).resize(function() {
    if (get_current_page() == 'balances') {
        resize_diagrams();
    }
});

function resize_diagrams() {
    // resize charts in tabs
    $.each(diagram_types, function(index, type) {
        var container = $('#' + type + '_container');
        var chart = container.highcharts();
        chart.setSize(container.parent().width(), container.parent().height(), false);
    });
}

function initialize_balance_diagrams() {
    $.each(diagram_types, function(index, type) {
        $('#' + type + '_container').highcharts({
            chart: {
                zoomType: 'xy'
            },
            title: {
                text: ''
            },
            xAxis: {
                categories: get_text('months')
            },
            yAxis: [{
                labels: {
                    format: '{value} €',
                    style: { color: Highcharts.getOptions().colors[1] }
                },
                title: {
                    text: 'Balances in €',
                    style: { color: Highcharts.getOptions().colors[1] }
                },
            }],
            plotOptions: {
                series: {
                    cursor: 'pointer',
                    point: {
                        events: {
                            click: function (e) {
                                $('#notice_container').empty();
                                var month = get_text('months').indexOf(e.currentTarget.category);
                                var year = get_year_from_string(this.series.name);
                                show_month_details(year, month);
                            }
                        }
                    },
                    marker: {
                        lineWidth: 1
                    }
                }
            },
            tooltip: {
                valueDecimals: 2
            },
            series: [],
            credits: {
                enabled: false
            }
        });
    });
}

function initialize_balance_diagrams_filters() {
    $.getJSON(api_base_url + 'history/', function(history_data) {
        $.each(history_data, function(index, year) {
            $('#diagram_filters').append(
                '\
                <input class="btn diagram_filter" type="checkbox" value="' + year + '">\
                ' + year + '');
        });
        $('.diagram_filter').change(function () {

            charts = [];
            $.each(diagram_types, function(index, type) {
                charts.push($('#' + type + '_container').highcharts());
            });
            var year = parseInt($(this).val());
            if ($(this).is(":checked")) {
                var found = false;
                $.each(charts, function(index, chart) {
                    $.each(chart.series, function(index2, series) {
                        if (series['name'].substr(series['name'].length - 4) == year) {
                            series.show(false);
                            found = true;
                        }
                    });
                });
                if (!found) {
                    $.getJSON(api_base_url + "balance/total/" + year + "/", function(data) {
                        cached_data[year] = data;
                        var balances = {
                            name: 'Total Balances in ' + year,
                            type: 'column',
                            data: []
                        };
                        var rewards = {
                            name: 'Total Rewards in ' + year,
                            type: 'column',
                            data: []
                        };
                        var costs = {
                            name: 'Total Costs in ' + year,
                            type: 'column',
                            data: [],
                        };
                        $.each(data, function(index, monthly_data) {
                            balances['data'].push(monthly_data.balance);
                            rewards['data'].push(monthly_data.rewards);
                            costs['data'].push(monthly_data.costs);
                        });
                        charts[0].addSeries(balances);
                        charts[1].addSeries(rewards);
                        charts[2].addSeries(costs);

                        // preselect tables details
                        if ($('#details_container').is(':empty')) {
                            show_month_details(year, data.length - 1);
                        }
                    });
                }
            } else {
                $.each(charts, function(index, chart) {
                    $.each(chart.series, function(index, series) {
                        if (get_year_from_string(series['name']) == year) {
                            series.hide(false);
                        }
                    });
                });
            }

            // if all series are unchecked, show all
            var all_unchecked = true;
            $(".diagram_filter").each(function() {
                if ($(this).is(":checked")) {
                    all_unchecked = false;
                }
            });
            if (all_unchecked) {
                $.each(charts, function(index, chart) {
                    $.each(chart.series, function(index, series) {
                        series.setVisible(true, false);
                    });
                });
            }

            // finally redraw all charts
            $.each(charts, function(index, chart) {
                chart.redraw();
            });
        });

        // preselect first filter
        $('.diagram_filter').first().parent().button('toggle');
    });
}

function show_month_details(year, month) {
    $.each(cached_data[year], function(index, monthly_data) {
        if (month == index) {
            update_balances_table(monthly_data, year, month);
            $('#selected_year').val(year);
            $('#selected_month').val(month);
        }
    });
}

function update_balances_table(data, year, month) {
    $.get('templates/balances_table.html', function(template) {
        var rendered = Mustache.render(template, {
            title: $.format.date(new Date(year, month, 1), "MMMM yyyy"),
            thermal_revenues: {
                text: get_text('thermal_revenues'),
                price: data['prices']['thermal_revenues'],
                value: data['kwh']['thermal_consumption'],
                total: Math.round(data['kwh']['thermal_consumption'] * data['prices']['thermal_revenues'] * 100)/100
            },
            warmwater_revenues: {
                text: get_text('warmwater_revenues'),
                price: data['prices']['warmwater_revenues'],
                value: data['kwh']['warmwater_consumption'],
                total: Math.round(data['kwh']['warmwater_consumption'] * data['prices']['warmwater_revenues'] * 100)/100
            },
            electrical_revenues: {
                text: get_text('electrical_revenues'),
                price: data['prices']['electrical_revenues'],
                value: data['kwh']['electrical_consumption'],
                total: Math.round(data['kwh']['electrical_consumption'] * data['prices']['electrical_revenues'] * 100)/100
            },
            electrical_infeed: {
                text: get_text('electrical_infeed'),
                price: data['prices']['feed_in_reward'] ,
                value: data['kwh']['electrical_infeed'],
                total: Math.round(data['kwh']['electrical_infeed'] * data['prices']['feed_in_reward'] * 100)/100
            },
            gas_consumption: {
                text: get_text('gas_consumption'),
                price: data['prices']['gas_costs'],
                value: data['kwh']['gas_consumption'],
                total: Math.round(data['kwh']['gas_consumption'] * data['prices']['gas_costs'] * 100)/100
            },
            electrical_purchase: {
                text: get_text('electrical_purchase'),
                price: data['prices']['electrical_costs'],
                value: data['kwh']['electrical_purchase'],
                total: Math.round(data['kwh']['electrical_purchase'] * data['prices']['electrical_costs'] * 100)/100
            },
            rewards: data['rewards'],
            costs: data['costs'],
            balance: data['balance'],
        });
        $('#details_container').html(rendered);
    }).done(function() {
        $('#export_button').click(function(event) {
            event.preventDefault();
            export_table($('#table_container'));
        });

        update_date_selection(year, month);
    });
}

function update_date_selection(selected_year, selected_month) {
    var month_options = "";
    $.each(get_text('months'), function(index, month) {
        month_options += '<option value="' + index + '" ' + (index == selected_month ? ' selected': '') + '>' + month + '</option>';
    });
    $('#selected_month').html(month_options);

    $('#selected_month').change(function() {
        show_month_details($('#selected_year').val(), $(this).val());
    });

    var year_options = "";
    $.each(cached_data, function(year, data) {
        year_options += '<option' + (year == selected_year ? ' selected': '') + '>' + year + '</option>';
    });
    $('#selected_year').html(year_options);

    $('#selected_year').change(function() {
        show_month_details($(this).val(), $('#selected_month').val());
    });
}

function get_year_from_string(string) {
    return string.substr(string.length - 4);
}
<|endoftext|>