<commit_before>var common     = require('../common');
var assert     = require('assert');

common.createConnection(function (err, db) {
	common.createKeysModelTable('test_multikey_find', db.driver.db, [ 'id1', 'id2', 'id3' ], function () {
		common.insertKeysModelData('test_multikey_find', db.driver.db, [
			{ id1 : 1, id2 : 1, id3: 1, name : 'test111' },
			{ id1 : 1, id2 : 2, id3: 3, name : 'test123' },
			{ id1 : 2, id2 : 3, id3: 1, name : 'test231' },
			{ id1 : 3, id2 : 1, id3: 2, name : 'test312' }
		], function (err) {
			if (err) throw err;

			var TestModel = db.define('test_multikey_find', common.getModelProperties(), {
				keys  : [ 'id1', 'id2', 'id3' ],
				cache : false
			});

			TestModel.get(1, 2, 3, function (err, item) {
				assert.equal(err, null);
				assert.equal(item.name, 'test123');

				item.name = 'tested';

				assert.throws(function () {
					item.id2 = 5;
				}, /cannot change id/i);

				item.save(function (err) {
					assert.equal(err, null);

					TestModel.get(1, 2, 3, function (err, item_copy1) {
						assert.equal(err, null);
						assert.equal(item_copy1.name, 'tested');

						item_copy1.remove(function () {
							assert.equal(err, null);

							TestModel.get(1, 2, 3, function (err, item_copy2) {
								assert.notEqual(err, null);
								assert.equal(err.message, "Not found");

								TestModel.exists(1, 2, 3, function (err, exists) {
									assert.equal(err, null);
									assert.equal(exists, false);

									TestModel.find().count(function (err, count) {
										assert.equal(err, null);
										assert.equal(count, 3);

										db.close();
									});
								});
							});
						});
					});
				});
			});
		});
	});
});
<commit_msg>Fixes test-multikey-base table<commit_after>var common     = require('../common');
var assert     = require('assert');

common.createConnection(function (err, db) {
	common.createKeysModelTable('test_multikey_base', db.driver.db, [ 'id1', 'id2', 'id3' ], function () {
		common.insertKeysModelData('test_multikey_base', db.driver.db, [
			{ id1 : 1, id2 : 1, id3: 1, name : 'test111' },
			{ id1 : 1, id2 : 2, id3: 3, name : 'test123' },
			{ id1 : 2, id2 : 3, id3: 1, name : 'test231' },
			{ id1 : 3, id2 : 1, id3: 2, name : 'test312' }
		], function (err) {
			if (err) throw err;

			var TestModel = db.define('test_multikey_base', common.getModelProperties(), {
				keys  : [ 'id1', 'id2', 'id3' ],
				cache : false
			});

			TestModel.get(1, 2, 3, function (err, item) {
				assert.equal(err, null);
				assert.equal(item.name, 'test123');

				item.name = 'tested';

				assert.throws(function () {
					item.id2 = 5;
				}, /cannot change id/i);

				item.save(function (err) {
					assert.equal(err, null);

					TestModel.get(1, 2, 3, function (err, item_copy1) {
						assert.equal(err, null);
						assert.equal(item_copy1.name, 'tested');

						item_copy1.remove(function () {
							assert.equal(err, null);

							TestModel.get(1, 2, 3, function (err, item_copy2) {
								assert.notEqual(err, null);
								assert.equal(err.message, "Not found");

								TestModel.exists(1, 2, 3, function (err, exists) {
									assert.equal(err, null);
									assert.equal(exists, false);

									TestModel.find().count(function (err, count) {
										assert.equal(err, null);
										assert.equal(count, 3);

										db.close();
									});
								});
							});
						});
					});
				});
			});
		});
	});
});
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2020 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.nanos.medusa.benchmark',
  name: 'MedusaBenchmark',
  implements: [ 'foam.nanos.bench.Benchmark' ],

  javaImports: [
    'foam.core.FObject',
    'foam.core.X',
    'foam.dao.ArraySink',
    'foam.dao.DAO',
    'foam.mlang.sink.Count',
    'foam.nanos.app.AppConfig',
    'foam.nanos.auth.LifecycleState',
    'foam.nanos.bench.Benchmark',
    'foam.nanos.boot.NSpec',
    'foam.nanos.logger.PrefixLogger',
    'foam.nanos.logger.Logger',
    'foam.nanos.logger.StdoutLogger',
    'foam.nanos.medusa.MedusaEntry',
    'foam.nanos.medusa.DaggerService',
    'foam.nanos.medusa.test.MedusaTestObject',
    'static foam.mlang.MLang.EQ',
    'java.util.UUID'
  ],

  properties: [
    {
      name: 'serviceName',
      class: 'String',
      value: 'medusaTestObjectDAO'
    },
    {
      name: 'logger',
      class: 'FObjectProperty',
      of: 'foam.nanos.logger.Logger',
      visibility: 'HIDDEN',
      javaFactory: `
      Logger logger = (Logger) getX().get("logger");
      if ( logger == null ) {
        logger = new StdoutLogger();
      }
      return new PrefixLogger(new Object[] {
        this.getClass().getSimpleName()
      }, logger);
      `
    }
  ],

  methods: [
    {
      name: 'setup',
      args: [
        {
          name: 'x',
          type: 'X'
        },
      ],
      javaCode: `
      // nop
      `
    },
    {
      name: 'execute',
      args: [
        {
          name: 'x',
          type: 'X'
        },
      ],
      javaCode: `
    AppConfig config = (AppConfig) x.get("appConfig");

    if ( config.getMode() == foam.nanos.app.Mode.PRODUCTION ) {
      return;
    }

    DAO dao = (DAO) x.get(getServiceName());
    MedusaTestObject test = new MedusaTestObject();
    test.setName(UUID.randomUUID().toString());
    dao.put(test);
      `
    },
    {
      name: 'teardown',
      args: [
        {
          name: 'x',
          type: 'X'
        },
        {
          name: 'stats',
          type: 'Map'
        }
      ],
      javaCode: `
      // nop
      `
    }
  ]
});
<commit_msg>Set description on test object to add more bytes<commit_after>/**
 * @license
 * Copyright 2020 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.nanos.medusa.benchmark',
  name: 'MedusaBenchmark',
  implements: [ 'foam.nanos.bench.Benchmark' ],

  javaImports: [
    'foam.core.FObject',
    'foam.core.X',
    'foam.dao.ArraySink',
    'foam.dao.DAO',
    'foam.mlang.sink.Count',
    'foam.nanos.app.AppConfig',
    'foam.nanos.auth.LifecycleState',
    'foam.nanos.bench.Benchmark',
    'foam.nanos.boot.NSpec',
    'foam.nanos.logger.PrefixLogger',
    'foam.nanos.logger.Logger',
    'foam.nanos.logger.StdoutLogger',
    'foam.nanos.medusa.MedusaEntry',
    'foam.nanos.medusa.DaggerService',
    'foam.nanos.medusa.test.MedusaTestObject',
    'static foam.mlang.MLang.EQ',
    'java.util.UUID'
  ],

  properties: [
    {
      name: 'serviceName',
      class: 'String',
      value: 'medusaTestObjectDAO'
    },
    {
      name: 'logger',
      class: 'FObjectProperty',
      of: 'foam.nanos.logger.Logger',
      visibility: 'HIDDEN',
      javaFactory: `
      Logger logger = (Logger) getX().get("logger");
      if ( logger == null ) {
        logger = new StdoutLogger();
      }
      return new PrefixLogger(new Object[] {
        this.getClass().getSimpleName()
      }, logger);
      `
    }
  ],

  methods: [
    {
      name: 'setup',
      args: [
        {
          name: 'x',
          type: 'X'
        },
      ],
      javaCode: `
      // nop
      `
    },
    {
      name: 'execute',
      args: [
        {
          name: 'x',
          type: 'X'
        },
      ],
      javaCode: `
    AppConfig config = (AppConfig) x.get("appConfig");

    if ( config.getMode() == foam.nanos.app.Mode.PRODUCTION ) {
      return;
    }

    DAO dao = (DAO) x.get(getServiceName());
    MedusaTestObject test = new MedusaTestObject();
    test.setName(UUID.randomUUID().toString());
    test.setDescription("MedusaTestObject");
    dao.put(test);
      `
    },
    {
      name: 'teardown',
      args: [
        {
          name: 'x',
          type: 'X'
        },
        {
          name: 'stats',
          type: 'Map'
        }
      ],
      javaCode: `
      // nop
      `
    }
  ]
});
<|endoftext|>


<commit_before>'use strict';
var isInit = true,
    helpers = require('../../utils/widgets/helper'),
    navigationProperty = require('../../utils/widgets/navigation-property'),
    // additional requires
    viewModel = require('./offlinePageView-view-model'),
	modOfflinePage = require('../../lib/modOfflinePage/modOfflinePage.js'),
	modBrowser = require('../../lib/modBrowser/modBrowser.js'),
	actionBarModule = require("ui/action-bar"),
	buttonModule = require("ui/button"),
	util = require('../../utils/MyUtil')
	;

// additional functions
function pageLoaded(args) {
    var page = args.object;

    helpers.platformInit(page);
    page.bindingContext = viewModel;
    // additional pageLoaded

    if (isInit) {
        isInit = false;

        // additional pageInit
    }
	loadItems();

	// NAVBUTTON - start
	var navButton = new actionBarModule.NavigationButton();
	navButton.text = 'Edit'
	navButton.height = 44;
	navButton.on(buttonModule.Button.tapEvent, function() {
		if(!editMode)
			navButton.text = 'Done';
		else
			navButton.text = 'Edit';

		editMode = !editMode;
	})
	util.setRightNavButton(page, navButton);
	// NAVBUTTON - end

}
function loadItems() {
    modOfflinePage.getList(function(items) {
        var menuItems = [];
        for(var i = 0; i < items.length; i++) {
            var item = items[i];
            menuItems.push({
                "title": "[" + item.title + "]",
                "item" : item,
                "icon": "\ue903"
            },);
        }
        viewModel.set('menuItems', menuItems);
    });
}

// START_CUSTOM_CODE_homeView
// Add custom code here. For more information about custom code, see http://docs.telerik.com/platform/screenbuilder/troubleshooting/how-to-keep-custom-code-changes
var view = require("ui/core/view");
function menuItemTap(args) {
    var sender = args.object;
    var parent = sender.parent;
    var menuItems = viewModel.get('menuItems');
    var menuItem = menuItems[args.index];
    var item = menuItem.item;
	//console.log(JSON.stringify(item));
	if(!editMode) {
		if(item.type == 'category') {
			var browser = modBrowser.createBrowser();
			browser.open(item.cat);
		}
		else if(item.type == 'item') {
			var browser = modBrowser.createBrowser();
			browser.open(item.item);
		}
	}
	else {
		var options = [];
		if(item.sourceURL != null && item.sourceURL != '') {
			options.push({id:'opt1',text:'Update from SourceURL',func:function() {
				util.frequest({
					url : item.sourceURL,
					callbackJSON : function(data) {
						item.cat = data;
						modOfflinePage.updateById(item.id, item, function() {
							console.log('saved offline page id = ' + item.id);
						});
					}
				});
			}});
		}
		options.push({id:'opt2',text:'Update title', func:function() {

		}});
		options.push({id:'opt3',text:'Delete', func:function() {
			var menuOptions = [];
			menuOptions.push({id:'opt1',text:'Yes, delete it',func:function() {
				modOfflinePage.deleteById(item.id, function() {
					console.log('deleted offline page id = ' + item.id);
				});
			}});
			util.showOptionDialog(menuOptions);
		}});
		util.showOptionDialog(options);
	}
}

// END_CUSTOM_CODE_homeView

var editMode = false;

exports.menuItemTap = menuItemTap;
exports.pageLoaded = pageLoaded;<commit_msg>#289 Offline page to edit title<commit_after>'use strict';
var isInit = true,
    helpers = require('../../utils/widgets/helper'),
    navigationProperty = require('../../utils/widgets/navigation-property'),
    // additional requires
    viewModel = require('./offlinePageView-view-model'),
	modOfflinePage = require('../../lib/modOfflinePage/modOfflinePage.js'),
	modBrowser = require('../../lib/modBrowser/modBrowser.js'),
	actionBarModule = require("ui/action-bar"),
	buttonModule = require("ui/button"),
	util = require('../../utils/MyUtil')
	;

// additional functions
function pageLoaded(args) {
    var page = args.object;

    helpers.platformInit(page);
    page.bindingContext = viewModel;
    // additional pageLoaded

    if (isInit) {
        isInit = false;

        // additional pageInit
    }
	loadItems();

	// NAVBUTTON - start
	var navButton = new actionBarModule.NavigationButton();
	navButton.text = 'Edit'
	navButton.height = 44;
	navButton.on(buttonModule.Button.tapEvent, function() {
		if(!editMode)
			navButton.text = 'Done';
		else
			navButton.text = 'Edit';

		editMode = !editMode;
	})
	util.setRightNavButton(page, navButton);
	// NAVBUTTON - end

}
function loadItems() {
    modOfflinePage.getList(function(items) {
        var menuItems = [];
        for(var i = 0; i < items.length; i++) {
            var item = items[i];
            menuItems.push({
                "title": "[" + item.title + "]",
                "item" : item,
                "icon": "\ue903"
            },);
        }
        viewModel.set('menuItems', menuItems);
    });
}

// START_CUSTOM_CODE_homeView
// Add custom code here. For more information about custom code, see http://docs.telerik.com/platform/screenbuilder/troubleshooting/how-to-keep-custom-code-changes
var view = require("ui/core/view");
function menuItemTap(args) {
    var sender = args.object;
    var parent = sender.parent;
    var menuItems = viewModel.get('menuItems');
    var menuItem = menuItems[args.index];
    var item = menuItem.item;
	//console.log(JSON.stringify(item));
	if(!editMode) {
		if(item.type == 'category') {
			var browser = modBrowser.createBrowser();
			browser.open(item.cat);
		}
		else if(item.type == 'item') {
			var browser = modBrowser.createBrowser();
			browser.open(item.item);
		}
	}
	else {
		var options = [];
		if(item.sourceURL != null && item.sourceURL != '') {
			options.push({id:'opt1',text:'Update from SourceURL',func:function() {
				util.frequest({
					url : item.sourceURL,
					callbackJSON : function(data) {
						item.cat = data;
						modOfflinePage.updateById(item.id, item, function() {
							console.log('saved offline page id = ' + item.id);
						});
					}
				});
			}});
		}
		options.push({id:'opt2',text:'Update title', func:function() {
			var dialogs = require("ui/dialogs");
			// Second argument is optional.
			dialogs.prompt("Please enter title - " + item.title, "").then(function (r) {
				console.log("Dialog result: " + r.result + ", text: " + r.text);
				item.title = r.text;
				modOfflinePage.updateById(item.id, item, function() {
					console.log('saved offline page id = ' + item.id);
					alert('Title updated');
				});
			});
		}});
		options.push({id:'opt3',text:'Delete', func:function() {
			var menuOptions = [];
			menuOptions.push({id:'opt1',text:'Yes, delete it',func:function() {
				modOfflinePage.deleteById(item.id, function() {
					console.log('deleted offline page id = ' + item.id);
				});
			}});
			util.showOptionDialog(menuOptions);
		}});
		util.showOptionDialog(options);
	}
}

// END_CUSTOM_CODE_homeView

var editMode = false;

exports.menuItemTap = menuItemTap;
exports.pageLoaded = pageLoaded;<|endoftext|>


<commit_before>const fs = require('fs-extra');
const globby = require('globby');
const uppercamelcase = require('uppercamelcase');
const path = require('path');
const cheerio = require('cheerio');
const prettier = require('prettier');
const SVGO = require('svgo');
const yaml = require('js-yaml');
const { getConfig } = require('../../build-tools/utils/config-store');

const svgo = new SVGO({
  plugins: [
    {
      removeViewBox: false,
    },
    {
      removeXMLNS: true,
    },
    {
      cleanupAttrs: true,
    },
    {
      removeDoctype: true,
    },
    {
      removeXMLProcInst: true,
    },
    {
      removeComments: true,
    },
    {
      removeMetadata: true,
    },
    {
      removeTitle: true,
    },
    {
      removeDesc: true,
    },
    {
      removeUselessDefs: true,
    },
    {
      removeEditorsNSData: true,
    },
    {
      removeEmptyAttrs: true,
    },
    {
      removeHiddenElems: true,
    },
    {
      removeEmptyText: true,
    },
    {
      removeEmptyContainers: true,
    },
    {
      removeViewBox: false,
    },
    {
      cleanupEnableBackground: true,
    },
    {
      convertStyleToAttrs: true,
    },
    {
      convertColors: true,
    },
    {
      convertPathData: true,
    },
    {
      convertTransform: true,
    },
    {
      removeUnknownsAndDefaults: true,
    },
    {
      removeNonInheritableGroupAttrs: true,
    },
    {
      removeUselessStrokeAndFill: true,
    },
    {
      removeUnusedNS: true,
    },
    {
      cleanupIDs: true,
    },
    {
      cleanupNumericValues: true,
    },
    {
      moveElemsAttrsToGroup: true,
    },
    {
      moveGroupAttrsToElems: true,
    },
    {
      collapseGroups: true,
    },
    {
      removeRasterImages: false,
    },
    {
      mergePaths: true,
    },
    {
      convertShapeToPath: true,
    },
    {
      sortAttrs: true,
    },
    {
      removeDimensions: true,
    },
  ],
});

const rootDir = path.join(__dirname);
const buildDir = path.join(rootDir, 'src/icons');

/**
 * Transpile Icons
 * @param {array} icons
 * @returns {Promise<[{ id, fileName, location, icon}]>} - Returns an array of objects about each icon with props: id, fileName, location, & icon
 */
async function transpileIcons(icons) {
  await fs.mkdirp(buildDir);

  return Promise.all(
    icons.map(async icon => {
      // icons.forEach(async (i) => {
      const svg = await fs.readFile(icon, 'utf-8');
      const id = path
        .basename(icon, '.svg')
        .replace(/ /g, '-')
        .replace('.colored', '-colored');

      const $ = cheerio.load(svg, {
        xmlMode: true,
      });

      const fileName = path
        .basename(icon)
        .replace(/ /g, '-')
        .replace('.colored', '-colored')
        .replace('.svg', '.js');
      const location = path.join(buildDir, fileName);

      $('*').each((index, el) => {
        Object.keys(el.attribs).forEach(x => {
          if (x === 'stroke') {
            $(el).attr(x, 'currentColor');
          }

          if (x === 'fill') {
            $(el).attr(x, 'currentColor');
          }
        });

        if (el.name === 'svg') {
          $(el).attr('otherProps', '...');
        }

        // Remove artboard rectangle that sometimes pops up in exported SVGs
        if ($(el).attr('id') === 'Rectangle-6') {
          $(el).remove();
        }

        $(el).removeAttr('xmlns:xlink');

        if ($(el).attr('xlink:href')) {
          const xlinkHrefVal = $(el).attr('xlink:href');
          $(el).removeAttr('xlink:href');
          $(el).attr('xlinkHref', xlinkHrefVal);
        }

        if ($(el).attr('xlink:href')) {
          const xlinkHrefVal = $(el).attr('xlink:href');
          $(el).removeAttr('xlink:href');
          $(el).attr('xlinkHref', xlinkHrefVal);
        }
      });

      const result = await svgo.optimize(svg);
      const optimizedSVG = result.data;

      const element = `
  import { h } from '@bolt/core/renderers';

  export const ${uppercamelcase(
    id,
  )} = ({ bgColor, fgColor, size, ...otherProps }) => {
      return (
        ${
          fileName.includes('-color')
            ? $(optimizedSVG)
                .toString()
                .replace('viewBox', '{...otherProps} viewBox') // tack on extra props next to viewBox attribute
                .replace('d="M0 0h24v24H0z"', '')
                .replace(/width=".*?"/, 'width={size}')
                .replace(/height=".*?"/, 'height={size}')
                .replace('otherProps="..."', '{...otherProps}')
            : $(optimizedSVG)
                .toString()
                .replace('fill="#FFF"', 'fill={fgColor}')
                .replace('stroke="#FFF"', 'stroke={fgColor}')
                .replace(new RegExp(/ stroke=".*?"/, 'g'), ' stroke={bgColor}')
                .replace(
                  new RegExp(/ fill="(?!#fff|none).*?"/, 'g'),
                  ' fill={bgColor}',
                )
                .replace('viewBox', '{...otherProps} viewBox') // tack on extra props next to viewBox attribute
                .replace('d="M0 0h24v24H0z"', '')
                .replace(/width=".*?"/, 'width={size}')
                .replace(/height=".*?"/, 'height={size}')
                .replace('otherProps="..."', '{...otherProps}')
        }
      )
};
`;

      const component = prettier.format(element, {
        singleQuote: true,
        trailingComma: 'es5',
        bracketSpacing: true,
        parser: 'flow',
      });

      await fs.outputFile(location, element, 'utf-8');
      // Later when we call `const icons = await transpileIcons(iconPaths);` - `icons` will be an array of these objects:
      return {
        location,
        id,
        icon,
        fileName,
      };
    }),
  );
}

function alphabetizeIconList(a, b) {
  if (a.id < b.id) return -1;
  if (a.id > b.id) return 1;
  return 0;
}

async function build() {
  try {
    const iconPaths = await globby(path.join(rootDir, 'src/svgs/**/*.svg'));
    await fs.remove(path.join(rootDir, 'src/icons')); // Clean folder
    await fs.outputFile(path.join(rootDir, 'src', 'index.js'), '', 'utf-8');
    const icons = await transpileIcons(iconPaths);
    const allExports = icons
      .sort(alphabetizeIconList) // we alphabetize the list so multiple compiles on same set doesn't result in a change that git notices
      .map(icon => `export * from './icons/${icon.id}';`); // building up `export` lines
    allExports.push(''); // Adding empty item to end of array so file has empty line at bottom to conform to `.editorconfig`
    await fs.outputFile(
      path.join(rootDir, 'src', 'index.js'),
      allExports.join('\n'),
      'utf-8',
    );
    generateFile(icons);
    console.log(`Built ${iconPaths.length} icons.`);
  } catch (error) {
    console.error(error);
    console.error(
      'Error trying to run "npm run build" for "@bolt/components-icons".',
    );
    process.exitCode = 1;
  }
}

async function generateFile(icons) {
  try {
    const config = await getConfig();
    const names = icons.map(icon => icon.id);
    const schema = yaml.safeLoad(
      fs.readFileSync('../bolt-icon/icon.schema.yml', 'utf8'),
    );
    schema.properties.name.enum = names;
    // update bolt-icon schema with newest icons from svgs folder
    await fs.writeFile('../bolt-icon/icon.schema.yml', yaml.safeDump(schema));
    // generate `icons.bolt.json` file with newest icons array
    await fs.writeFile(
      path.join(__dirname, '../../../', config.dataDir, 'icons.bolt.json'),
      JSON.stringify(names, null, 4),
    );
    console.log('Config:', config);
    console.log('Dir Name:', __dirname);
    console.log(`Icon Schema updated and Icons JSON generated.`);
  } catch (error) {
    console.error(error);
    console.error(
      'Error trying to generate Icon YAML document for "@bolt/components-icon".',
    );
    process.exitCode = 1;
  }
}

build();
<commit_msg>test: Path test<commit_after>const fs = require('fs-extra');
const globby = require('globby');
const uppercamelcase = require('uppercamelcase');
const path = require('path');
const cheerio = require('cheerio');
const prettier = require('prettier');
const SVGO = require('svgo');
const yaml = require('js-yaml');
const { getConfig } = require('../../build-tools/utils/config-store');

const svgo = new SVGO({
  plugins: [
    {
      removeViewBox: false,
    },
    {
      removeXMLNS: true,
    },
    {
      cleanupAttrs: true,
    },
    {
      removeDoctype: true,
    },
    {
      removeXMLProcInst: true,
    },
    {
      removeComments: true,
    },
    {
      removeMetadata: true,
    },
    {
      removeTitle: true,
    },
    {
      removeDesc: true,
    },
    {
      removeUselessDefs: true,
    },
    {
      removeEditorsNSData: true,
    },
    {
      removeEmptyAttrs: true,
    },
    {
      removeHiddenElems: true,
    },
    {
      removeEmptyText: true,
    },
    {
      removeEmptyContainers: true,
    },
    {
      removeViewBox: false,
    },
    {
      cleanupEnableBackground: true,
    },
    {
      convertStyleToAttrs: true,
    },
    {
      convertColors: true,
    },
    {
      convertPathData: true,
    },
    {
      convertTransform: true,
    },
    {
      removeUnknownsAndDefaults: true,
    },
    {
      removeNonInheritableGroupAttrs: true,
    },
    {
      removeUselessStrokeAndFill: true,
    },
    {
      removeUnusedNS: true,
    },
    {
      cleanupIDs: true,
    },
    {
      cleanupNumericValues: true,
    },
    {
      moveElemsAttrsToGroup: true,
    },
    {
      moveGroupAttrsToElems: true,
    },
    {
      collapseGroups: true,
    },
    {
      removeRasterImages: false,
    },
    {
      mergePaths: true,
    },
    {
      convertShapeToPath: true,
    },
    {
      sortAttrs: true,
    },
    {
      removeDimensions: true,
    },
  ],
});

const rootDir = path.join(__dirname);
const buildDir = path.join(rootDir, 'src/icons');

/**
 * Transpile Icons
 * @param {array} icons
 * @returns {Promise<[{ id, fileName, location, icon}]>} - Returns an array of objects about each icon with props: id, fileName, location, & icon
 */
async function transpileIcons(icons) {
  await fs.mkdirp(buildDir);

  return Promise.all(
    icons.map(async icon => {
      // icons.forEach(async (i) => {
      const svg = await fs.readFile(icon, 'utf-8');
      const id = path
        .basename(icon, '.svg')
        .replace(/ /g, '-')
        .replace('.colored', '-colored');

      const $ = cheerio.load(svg, {
        xmlMode: true,
      });

      const fileName = path
        .basename(icon)
        .replace(/ /g, '-')
        .replace('.colored', '-colored')
        .replace('.svg', '.js');
      const location = path.join(buildDir, fileName);

      $('*').each((index, el) => {
        Object.keys(el.attribs).forEach(x => {
          if (x === 'stroke') {
            $(el).attr(x, 'currentColor');
          }

          if (x === 'fill') {
            $(el).attr(x, 'currentColor');
          }
        });

        if (el.name === 'svg') {
          $(el).attr('otherProps', '...');
        }

        // Remove artboard rectangle that sometimes pops up in exported SVGs
        if ($(el).attr('id') === 'Rectangle-6') {
          $(el).remove();
        }

        $(el).removeAttr('xmlns:xlink');

        if ($(el).attr('xlink:href')) {
          const xlinkHrefVal = $(el).attr('xlink:href');
          $(el).removeAttr('xlink:href');
          $(el).attr('xlinkHref', xlinkHrefVal);
        }

        if ($(el).attr('xlink:href')) {
          const xlinkHrefVal = $(el).attr('xlink:href');
          $(el).removeAttr('xlink:href');
          $(el).attr('xlinkHref', xlinkHrefVal);
        }
      });

      const result = await svgo.optimize(svg);
      const optimizedSVG = result.data;

      const element = `
  import { h } from '@bolt/core/renderers';

  export const ${uppercamelcase(
    id,
  )} = ({ bgColor, fgColor, size, ...otherProps }) => {
      return (
        ${
          fileName.includes('-color')
            ? $(optimizedSVG)
                .toString()
                .replace('viewBox', '{...otherProps} viewBox') // tack on extra props next to viewBox attribute
                .replace('d="M0 0h24v24H0z"', '')
                .replace(/width=".*?"/, 'width={size}')
                .replace(/height=".*?"/, 'height={size}')
                .replace('otherProps="..."', '{...otherProps}')
            : $(optimizedSVG)
                .toString()
                .replace('fill="#FFF"', 'fill={fgColor}')
                .replace('stroke="#FFF"', 'stroke={fgColor}')
                .replace(new RegExp(/ stroke=".*?"/, 'g'), ' stroke={bgColor}')
                .replace(
                  new RegExp(/ fill="(?!#fff|none).*?"/, 'g'),
                  ' fill={bgColor}',
                )
                .replace('viewBox', '{...otherProps} viewBox') // tack on extra props next to viewBox attribute
                .replace('d="M0 0h24v24H0z"', '')
                .replace(/width=".*?"/, 'width={size}')
                .replace(/height=".*?"/, 'height={size}')
                .replace('otherProps="..."', '{...otherProps}')
        }
      )
};
`;

      const component = prettier.format(element, {
        singleQuote: true,
        trailingComma: 'es5',
        bracketSpacing: true,
        parser: 'flow',
      });

      await fs.outputFile(location, element, 'utf-8');
      // Later when we call `const icons = await transpileIcons(iconPaths);` - `icons` will be an array of these objects:
      return {
        location,
        id,
        icon,
        fileName,
      };
    }),
  );
}

function alphabetizeIconList(a, b) {
  if (a.id < b.id) return -1;
  if (a.id > b.id) return 1;
  return 0;
}

async function build() {
  try {
    const iconPaths = await globby(path.join(rootDir, 'src/svgs/**/*.svg'));
    await fs.remove(path.join(rootDir, 'src/icons')); // Clean folder
    await fs.outputFile(path.join(rootDir, 'src', 'index.js'), '', 'utf-8');
    const icons = await transpileIcons(iconPaths);
    const allExports = icons
      .sort(alphabetizeIconList) // we alphabetize the list so multiple compiles on same set doesn't result in a change that git notices
      .map(icon => `export * from './icons/${icon.id}';`); // building up `export` lines
    allExports.push(''); // Adding empty item to end of array so file has empty line at bottom to conform to `.editorconfig`
    await fs.outputFile(
      path.join(rootDir, 'src', 'index.js'),
      allExports.join('\n'),
      'utf-8',
    );
    generateFile(icons);
    console.log(`Built ${iconPaths.length} icons.`);
  } catch (error) {
    console.error(error);
    console.error(
      'Error trying to run "npm run build" for "@bolt/components-icons".',
    );
    process.exitCode = 1;
  }
}

async function generateFile(icons) {
  try {
    const config = await getConfig();
    const names = icons.map(icon => icon.id);
    const schema = yaml.safeLoad(
      fs.readFileSync('../bolt-icon/icon.schema.yml', 'utf8'),
    );
    schema.properties.name.enum = names;
    console.log('Config:', config);
    console.log('Dir Name:', __dirname);
    // update bolt-icon schema with newest icons from svgs folder
    await fs.writeFile('../bolt-icon/icon.schema.yml', yaml.safeDump(schema));
    // generate `icons.bolt.json` file with newest icons array
    await fs.writeFile(
      path.join(__dirname, '../../../', config.dataDir, 'icons.bolt.json'),
      JSON.stringify(names, null, 4),
    );
    console.log(`Icon Schema updated and Icons JSON generated.`);
  } catch (error) {
    console.error(error);
    console.error(
      'Error trying to generate Icon YAML document for "@bolt/components-icon".',
    );
    process.exitCode = 1;
  }
}

build();
<|endoftext|>


<commit_before>'use strict';

module.exports = {
	db: process.env.MONGOHQ_URL || process.env.MONGOLAB_URI || 'mongodb://' + (process.env.DB_1_PORT_27017_TCP_ADDR || 'localhost') + '/mean',
	port: process.env.PORT || 80,
	log: {
		// Can specify one of 'combined', 'common', 'dev', 'short', 'tiny'
		format: 'combined',
		// Stream defaults to process.stdout
		// Uncomment to enable logging to a log on the file system
		options: {
			stream: 'access.log'
		}
	},
	assets: {
		lib: {
			css: [
				'public/lib/bootstrap/dist/css/bootstrap.min.css',
				'public/lib/bootstrap/dist/css/bootstrap-theme.min.css',
			],
			js: [
				'public/lib/angular/angular.min.js',
				'public/lib/angular-resource/angular-resource.min.js',
				'public/lib/angular-animate/angular-animate.min.js',
				'public/lib/angular-ui-router/release/angular-ui-router.min.js',
				'public/lib/angular-ui-utils/ui-utils.min.js',
				'public/lib/angular-bootstrap/ui-bootstrap-tpls.min.js'
			]
		},
		css: 'public/dist/application.min.css',
		js: 'public/dist/application.min.js'
	},
	facebook: {
		clientID: process.env.FACEBOOK_ID || 'APP_ID',
		clientSecret: process.env.FACEBOOK_SECRET || 'APP_SECRET',
		callbackURL: '/auth/facebook/callback'
	},
	twitter: {
		clientID: process.env.TWITTER_KEY || 'CONSUMER_KEY',
		clientSecret: process.env.TWITTER_SECRET || 'CONSUMER_SECRET',
		callbackURL: '/auth/twitter/callback'
	},
	google: {
		clientID: process.env.GOOGLE_ID || 'APP_ID',
		clientSecret: process.env.GOOGLE_SECRET || 'APP_SECRET',
		callbackURL: '/auth/google/callback'
	},
	linkedin: {
		clientID: process.env.LINKEDIN_ID || 'APP_ID',
		clientSecret: process.env.LINKEDIN_SECRET || 'APP_SECRET',
		callbackURL: '/auth/linkedin/callback'
	},
	github: {
		clientID: process.env.GITHUB_ID || 'APP_ID',
		clientSecret: process.env.GITHUB_SECRET || 'APP_SECRET',
		callbackURL: '/auth/github/callback'
	},
	mailer: {
		from: process.env.MAILER_FROM || 'MAILER_FROM',
		options: {
			service: process.env.MAILER_SERVICE_PROVIDER || 'MAILER_SERVICE_PROVIDER',
			auth: {
				user: process.env.MAILER_EMAIL_ID || 'MAILER_EMAIL_ID',
				pass: process.env.MAILER_PASSWORD || 'MAILER_PASSWORD'
			}
		}
	}
};
<commit_msg>fix production config<commit_after>'use strict';

module.exports = {
	db: 'localhost/ekeague',
	port: process.env.PORT || 80,
	log: {
		// Can specify one of 'combined', 'common', 'dev', 'short', 'tiny'
		format: 'combined',
		// Stream defaults to process.stdout
		// Uncomment to enable logging to a log on the file system
		options: {
			stream: 'access.log'
		}
	},
	assets: {
		lib: {
			css: [
				'public/lib/bootstrap/dist/css/bootstrap.min.css',
				'public/lib/bootstrap/dist/css/bootstrap-theme.min.css',
			],
			js: [
				'public/lib/angular/angular.min.js',
				'public/lib/angular-resource/angular-resource.min.js',
				'public/lib/angular-animate/angular-animate.min.js',
				'public/lib/angular-ui-router/release/angular-ui-router.min.js',
				'public/lib/angular-ui-utils/ui-utils.min.js',
				'public/lib/angular-bootstrap/ui-bootstrap-tpls.min.js'
				'public/lib/socket.io-client/socket.io.js',
        'public/lib/angular-scroll-glue/src/scrollglue.js'
			]
		},
		css: 'public/dist/application.min.css',
		js: 'public/dist/application.min.js'
	},
	mailer: {
		from: process.env.MAILER_FROM || 'MAILER_FROM',
		options: {
			service: process.env.MAILER_SERVICE_PROVIDER || 'MAILER_SERVICE_PROVIDER',
			auth: {
				user: process.env.MAILER_EMAIL_ID || 'MAILER_EMAIL_ID',
				pass: process.env.MAILER_PASSWORD || 'MAILER_PASSWORD'
			}
		}
	}
};
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2020 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.u2.crunch.wizardflow',
  name: 'CheckPendingAgent',

  implements: [
    'foam.core.ContextAgent',
    'foam.mlang.Expressions'
  ],

  imports: [
    'capabilityDAO',
    'capabilities',
    'crunchService',
    'ctrl',
    'rootCapability',
    'sequence',
    'subject'
  ],

  exports: [
    'cancelled'
  ],

  requires: [
    'foam.log.LogLevel',
    'foam.nanos.crunch.AgentCapabilityJunction',
    'foam.nanos.crunch.CapabilityJunctionStatus'
  ],

  properties: [
    {
      name: 'cancelled',
      class: 'Boolean'
    },
    {
      name: 'showToast',
      class: 'Boolean'
    }
  ],

  messages: [
    { name: 'CANNOT_OPEN_GRANTED', message: 'This capability has already been granted to you' },
    { name: 'CANNOT_OPEN_PENDING', message: 'This capability is awaiting approval, updates are not permitted at this time' },
    { name: 'CANNOT_OPEN_ACTION_PENDING', message: 'This capability is awaiting review, updates are not permitted at this time' }
  ],

  methods: [
    // If Property expressions ever unwrap promises this method can be blank.
    async function execute() {
      var ucj = await this.crunchService.getJunction(null, this.rootCapability.id);

      var shouldReopen = false;
      if ( ucj.status !== this.CapabilityJunctionStatus.AVAILABLE ) {
        var statusPending = ucj.status === this.CapabilityJunctionStatus.PENDING;
        var shouldReopen = await this.crunchService.maybeReopen(this.ctrl.__subContext__, ucj.targetId);
        if ( ! shouldReopen && this.showToast ) {
          var message = statusPending ? this.CANNOT_OPEN_PENDING : this.CANNOT_OPEN_GRANTED;
          this.ctrl.notify(message, '', this.LogLevel.INFO, true);
          this.cancelled = true;
          this.sequence.endSequence();
          return;
        }
      }
      if ( shouldReopen && this.capabilities.length < 1 && this.showToast ) {
        // This is here because of a CertifyDataReviewed capability.
        this.ctrl.notify(this.CANNOT_OPEN_ACTION_PENDING);
        this.cancelled = true;
        this.sequence.endSequence();
      }
    }
  ]
});
<commit_msg>end sequence<commit_after>/**
 * @license
 * Copyright 2020 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.u2.crunch.wizardflow',
  name: 'CheckPendingAgent',

  implements: [
    'foam.core.ContextAgent',
    'foam.mlang.Expressions'
  ],

  imports: [
    'capabilityDAO',
    'capabilities',
    'crunchService',
    'ctrl',
    'rootCapability',
    'sequence',
    'subject'
  ],

  exports: [
    'cancelled'
  ],

  requires: [
    'foam.log.LogLevel',
    'foam.nanos.crunch.AgentCapabilityJunction',
    'foam.nanos.crunch.CapabilityJunctionStatus'
  ],

  properties: [
    {
      name: 'cancelled',
      class: 'Boolean'
    },
    {
      name: 'showToast',
      class: 'Boolean'
    }
  ],

  messages: [
    { name: 'CANNOT_OPEN_GRANTED', message: 'This capability has already been granted to you' },
    { name: 'CANNOT_OPEN_PENDING', message: 'This capability is awaiting approval, updates are not permitted at this time' },
    { name: 'CANNOT_OPEN_ACTION_PENDING', message: 'This capability is awaiting review, updates are not permitted at this time' }
  ],

  methods: [
    // If Property expressions ever unwrap promises this method can be blank.
    async function execute() {
      var ucj = await this.crunchService.getJunction(null, this.rootCapability.id);

      var shouldReopen = false;
      if ( ucj.status !== this.CapabilityJunctionStatus.AVAILABLE ) {
        var statusPending = ucj.status === this.CapabilityJunctionStatus.PENDING;
        var shouldReopen = await this.crunchService.maybeReopen(this.ctrl.__subContext__, ucj.targetId);

        if ( ! shouldReopen && this.showToast ) {
          var message = statusPending ? this.CANNOT_OPEN_PENDING : this.CANNOT_OPEN_GRANTED;
          this.ctrl.notify(message, '', this.LogLevel.INFO, true);
          this.cancelled = true;
          this.sequence.endSequence();
          return;
        }
      }
      if ( shouldReopen && this.capabilities.length < 1 && this.showToast ) {
        // This is here because of a CertifyDataReviewed capability.
        this.ctrl.notify(this.CANNOT_OPEN_ACTION_PENDING);
        this.cancelled = true;
        this.sequence.endSequence();
      }
      if ( ! shouldReopen && statusPending ) {
        this.cancelled = true;
        this.sequence.endSequence();
      }
    }
  ]
});
<|endoftext|>


<commit_before>// Copyright 2013-2015, University of Colorado Boulder

/*
 * A bucket that can be used to store spherical objects.  Manages the addition and removal of the spheres, stacks them
 * as they are added, and manages the stack as spheres are removed.
 *
 * This expects the spheres to have certain properties, please inspect the code to understand the 'contract' between the
 * bucket and the spheres.
 *
 * @author John Blanco
 */
define( function( require ) {
  'use strict';

  // modules
  var cleanArray = require( 'PHET_CORE/cleanArray' );
  var Vector2 = require( 'DOT/Vector2' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Bucket = require( 'PHETCOMMON/model/Bucket' );
  var phetcommon = require( 'PHETCOMMON/phetcommon' );

  /**
   * @param {Object} options
   * @constructor
   */
  function SphereBucket( options ) {
    Bucket.call( this, options );
    options = _.extend( {
      sphereRadius: 10,  // expected radius of the spheres that will be placed in this bucket
      usableWidthProportion: 1.0  // proportion of the bucket width that the spheres can occupy
    }, options );

    this._sphereRadius = options.sphereRadius;
    this._usableWidthProportion = options.usableWidthProportion;

    // Empirically determined, for positioning particles inside the bucket.
    this._verticalParticleOffset = options.verticalParticleOffset || -this._sphereRadius * 0.4;

    // particles managed by this bucket
    this._particles = [];
  }

  phetcommon.register( 'SphereBucket', SphereBucket );

  // Inherit from base type.
  inherit( Bucket, SphereBucket, {

    // @public
    addParticleFirstOpen: function( particle, animate ) {
      particle.destination = this.getFirstOpenLocation();
      this.addParticle( particle, animate );
    },

    // @public
    addParticleNearestOpen: function( particle, animate ) {
      particle.destination = this.getNearestOpenLocation( particle.destination );
      this.addParticle( particle, animate );
    },

    // @private
    addParticle: function( particle, animate ) {
      if ( !animate ) {
        particle.position = particle.destination;
      }
      this._particles.push( particle );
      var thisBucket = this;
      var particleRemovedListener = function( userControlled ) {
        thisBucket.removeParticle( particle );
        particle.userControlledProperty.unlink( particleRemovedListener );
        delete particle.bucketRemovalListener;
      };
      particle.userControlledProperty.lazyLink( particleRemovedListener );
      particle.bucketRemovalListener = particleRemovedListener; // Attach to the particle to aid unlinking in some cases.
    },

    // @public
    removeParticle: function( particle, skipLayout ) {
      if ( this._particles.indexOf( particle ) === -1 ) {
        console.log( 'Error: Attempt to remove particle not contained in bucket, ignoring.' );
        return;
      }
      this._particles = _.without( this._particles, particle );
      if ( !skipLayout ) {
        this.relayoutBucketParticles();
      }
    },

    // @public
    containsParticle: function( particle ) {
      return this._particles.indexOf( particle ) !== -1;
    },

    // @public
    extractClosestParticle: function( location ) {
      var closestParticle = null;
      this._particles.forEach( function( particle ) {
        if ( closestParticle === null || closestParticle.position.distance( location ) > particle.position.distance( location ) ) {
          closestParticle = particle;
        }
      } );
      if ( closestParticle !== null ) {
        // The particle is removed by setting 'userControlled' to true.  This
        // relies on the listener that was added when the particle was placed
        // into the bucket.
        closestParticle.userControlled = true;
      }
      return closestParticle;
    },

    // @public
    getParticleList: function() { return this._particles; },

    // @public
    reset: function() {
      this._particles.forEach( function( particle ) {
        // Remove listeners that are watching for removal from bucket.
        if ( typeof( particle.bucketRemovalListener ) === 'function' ) {
          particle.userControlledProperty.unlink( particle.bucketRemovalListener );
          delete particle.bucketRemovalListener;
        }
      } );
      cleanArray( this._particles );
    },

    // @private
    isPositionOpen: function( position ) {
      var positionOpen = true;
      for ( var i = 0; i < this._particles.length; i++ ) {
        var particle = this._particles[ i ];
        if ( particle.destination.equals( position ) ) {
          positionOpen = false;
          break;
        }
      }
      return positionOpen;
    },

    // @private
    getFirstOpenLocation: function() {
      var openLocation = Vector2.ZERO;
      var usableWidth = this.size.width * this._usableWidthProportion - 2 * this._sphereRadius;
      var offsetFromBucketEdge = ( this.size.width - usableWidth ) / 2 + this._sphereRadius;
      var numParticlesInLayer = Math.floor( usableWidth / ( this._sphereRadius * 2 ) );
      var row = 0;
      var positionInLayer = 0;
      var found = false;
      while ( !found ) {
        var testLocation = new Vector2( this.position.x - this.size.width / 2 + offsetFromBucketEdge + positionInLayer * 2 * this._sphereRadius,
          this.getYPositionForLayer( row ) );
        if ( this.isPositionOpen( testLocation ) ) {
          // We found a location that is open.
          openLocation = testLocation;
          found = true;
        }
        else {
          positionInLayer++;
          if ( positionInLayer >= numParticlesInLayer ) {
            // Move to the next layer.
            row++;
            positionInLayer = 0;
            numParticlesInLayer--;
            offsetFromBucketEdge += this._sphereRadius;
            if ( numParticlesInLayer === 0 ) {
              // This algorithm doesn't handle the situation where
              // more particles are added than can be stacked into
              // a pyramid of the needed size, but so far it hasn't
              // needed to.  If this requirement changes, the
              // algorithm will need to change too.
              numParticlesInLayer = 1;
              offsetFromBucketEdge -= this._sphereRadius;
            }
          }
        }
      }
      return openLocation;
    },

    // @private
    getLayerForYPosition: function( yPosition ) {
      return Math.abs( Math.round( ( yPosition - ( this.position.y + this._verticalParticleOffset ) ) / ( this._sphereRadius * 2 * 0.866 ) ) );
    },

    /*
     * Get the nearest open location to the provided current location.  This is used for particle stacking.
     *
     * @param {Vector2} position
     * @return {Vector2}
     * @private
     */
    getNearestOpenLocation: function( position ) {
      // Determine the highest occupied layer.  The bottom layer is 0.
      var highestOccupiedLayer = 0;
      var self = this;
      _.each( this._particles, function( particle ) {
        var layer = self.getLayerForYPosition( particle.destination.y );
        if ( layer > highestOccupiedLayer ) {
          highestOccupiedLayer = layer;
        }
      } );

      // Make a list of all open locations in the occupied layers.
      var openLocations = [];
      var usableWidth = this.size.width * this._usableWidthProportion - 2 * this._sphereRadius;
      var offsetFromBucketEdge = ( this.size.width - usableWidth ) / 2 + this._sphereRadius;
      var numParticlesInLayer = Math.floor( usableWidth / ( this._sphereRadius * 2 ) );

      // Loop, searching for open positions in the particle stack.
      for ( var layer = 0; layer <= highestOccupiedLayer + 1; layer++ ) {

        // Add all open locations in the current layer.
        for ( var positionInLayer = 0; positionInLayer < numParticlesInLayer; positionInLayer++ ) {
          var testPosition = new Vector2( this.position.x - this.size.width / 2 + offsetFromBucketEdge + positionInLayer * 2 * this._sphereRadius,
            this.getYPositionForLayer( layer ) );
          if ( this.isPositionOpen( testPosition ) ) {

            // We found a location that is unoccupied.
            if ( layer === 0 || this.countSupportingParticles( testPosition ) === 2 ) {
              // This is a valid open location.
              openLocations.push( testPosition );
            }
          }
        }

        // Adjust variables for the next layer.
        numParticlesInLayer--;
        offsetFromBucketEdge += this._sphereRadius;
        if ( numParticlesInLayer === 0 ) {
          // If the stacking pyramid is full, meaning that there are
          // no locations that are open within it, this algorithm
          // classifies the locations directly above the top of the
          // pyramid as being open.  This would result in a stack
          // of particles with a pyramid base.  So far, this hasn't
          // been a problem, but this limitation may limit
          // reusability of this algorithm.
          numParticlesInLayer = 1;
          offsetFromBucketEdge -= this._sphereRadius;
        }
      }

      // Find the closest open location to the provided current location.
      // Only the X-component is used for this determination, because if
      // the Y-component is used the particles often appear to fall sideways
      // when released above the bucket, which just looks weird.
      var closestOpenLocation = openLocations[ 0 ] || Vector2.ZERO;

      _.each( openLocations, function( location ) {
        if ( location.distance( position ) < closestOpenLocation.distance( position ) ) {
          // This location is closer.
          closestOpenLocation = location;
        }
      } );
      return closestOpenLocation;
    },

    // @private
    getYPositionForLayer: function( layer ) {
      return this.position.y + this._verticalParticleOffset + layer * this._sphereRadius * 2 * 0.866;
    },

    /*
     * Determine whether a particle is 'dangling', i.e. hanging above an open
     * space in the stack of particles.  Dangling particles should fall.
     * @private
     */
    isDangling: function( particle ) {
      var onBottomRow = particle.destination.y === this.position.y + this._verticalParticleOffset;
      return !onBottomRow && this.countSupportingParticles( particle.destination ) < 2;
    },

    // @private
    countSupportingParticles: function( position ) {
      var count = 0;
      for ( var i = 0; i < this._particles.length; i++ ) {
        var p = this._particles[ i ];
        if ( p.destination.y < position.y && // Must be in a lower layer
             p.destination.distance( position ) < this._sphereRadius * 3 ) {
          // Must be a supporting particle.
          count++;
        }
      }
      return count;
    },

    // @private
    relayoutBucketParticles: function() {
      var particleMoved;
      do {
        for ( var i = 0; i < this._particles.length; i++ ) {
          particleMoved = false;
          var particle = this._particles[ i ];
          if ( this.isDangling( particle ) ) {
            particle.destination = this.getNearestOpenLocation( particle.destination );
            particleMoved = true;
            break;
          }
        }
      } while ( particleMoved );
    }

  } );

  return SphereBucket;
} );
<commit_msg>Instrumented symbol-to-schematic game type, see https://github.com/phetsims/build-an-atom/issues/119<commit_after>// Copyright 2013-2015, University of Colorado Boulder

/*
 * A bucket that can be used to store spherical objects.  Manages the addition and removal of the spheres, stacks them
 * as they are added, and manages the stack as spheres are removed.
 *
 * This expects the spheres to have certain properties, please inspect the code to understand the 'contract' between the
 * bucket and the spheres.
 *
 * @author John Blanco
 */
define( function( require ) {
  'use strict';

  // modules
  var cleanArray = require( 'PHET_CORE/cleanArray' );
  var Vector2 = require( 'DOT/Vector2' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Bucket = require( 'PHETCOMMON/model/Bucket' );
  var phetcommon = require( 'PHETCOMMON/phetcommon' );

  /**
   * @param {Object} options
   * @constructor
   */
  function SphereBucket( options ) {
    Bucket.call( this, options );
    options = _.extend( {
      tandemName: null,
      sphereRadius: 10,  // expected radius of the spheres that will be placed in this bucket
      usableWidthProportion: 1.0  // proportion of the bucket width that the spheres can occupy
    }, options );
    this.tandemName = options.tandemName;

    this._sphereRadius = options.sphereRadius;
    this._usableWidthProportion = options.usableWidthProportion;

    // Empirically determined, for positioning particles inside the bucket.
    this._verticalParticleOffset = options.verticalParticleOffset || -this._sphereRadius * 0.4;

    // particles managed by this bucket
    this._particles = [];
  }

  phetcommon.register( 'SphereBucket', SphereBucket );

  // Inherit from base type.
  inherit( Bucket, SphereBucket, {

    // @public
    addParticleFirstOpen: function( particle, animate ) {
      particle.destination = this.getFirstOpenLocation();
      this.addParticle( particle, animate );
    },

    // @public
    addParticleNearestOpen: function( particle, animate ) {
      particle.destination = this.getNearestOpenLocation( particle.destination );
      this.addParticle( particle, animate );
    },

    // @private
    addParticle: function( particle, animate ) {
      if ( !animate ) {
        particle.position = particle.destination;
      }
      this._particles.push( particle );
      var thisBucket = this;
      var particleRemovedListener = function( userControlled ) {
        thisBucket.removeParticle( particle );
        particle.userControlledProperty.unlink( particleRemovedListener );
        delete particle.bucketRemovalListener;
      };
      particle.userControlledProperty.lazyLink( particleRemovedListener );
      particle.bucketRemovalListener = particleRemovedListener; // Attach to the particle to aid unlinking in some cases.
    },

    // @public
    removeParticle: function( particle, skipLayout ) {
      if ( this._particles.indexOf( particle ) === -1 ) {
        console.log( 'Error: Attempt to remove particle not contained in bucket, ignoring.' );
        return;
      }
      this._particles = _.without( this._particles, particle );
      if ( !skipLayout ) {
        this.relayoutBucketParticles();
      }
    },

    // @public
    containsParticle: function( particle ) {
      return this._particles.indexOf( particle ) !== -1;
    },

    // @public
    extractClosestParticle: function( location ) {
      var closestParticle = null;
      this._particles.forEach( function( particle ) {
        if ( closestParticle === null || closestParticle.position.distance( location ) > particle.position.distance( location ) ) {
          closestParticle = particle;
        }
      } );
      if ( closestParticle !== null ) {
        // The particle is removed by setting 'userControlled' to true.  This
        // relies on the listener that was added when the particle was placed
        // into the bucket.
        closestParticle.userControlled = true;
      }
      return closestParticle;
    },

    // @public
    getParticleList: function() { return this._particles; },

    // @public
    reset: function() {
      this._particles.forEach( function( particle ) {
        // Remove listeners that are watching for removal from bucket.
        if ( typeof( particle.bucketRemovalListener ) === 'function' ) {
          particle.userControlledProperty.unlink( particle.bucketRemovalListener );
          delete particle.bucketRemovalListener;
        }
      } );
      cleanArray( this._particles );
    },

    // @private
    isPositionOpen: function( position ) {
      var positionOpen = true;
      for ( var i = 0; i < this._particles.length; i++ ) {
        var particle = this._particles[ i ];
        if ( particle.destination.equals( position ) ) {
          positionOpen = false;
          break;
        }
      }
      return positionOpen;
    },

    // @private
    getFirstOpenLocation: function() {
      var openLocation = Vector2.ZERO;
      var usableWidth = this.size.width * this._usableWidthProportion - 2 * this._sphereRadius;
      var offsetFromBucketEdge = ( this.size.width - usableWidth ) / 2 + this._sphereRadius;
      var numParticlesInLayer = Math.floor( usableWidth / ( this._sphereRadius * 2 ) );
      var row = 0;
      var positionInLayer = 0;
      var found = false;
      while ( !found ) {
        var testLocation = new Vector2( this.position.x - this.size.width / 2 + offsetFromBucketEdge + positionInLayer * 2 * this._sphereRadius,
          this.getYPositionForLayer( row ) );
        if ( this.isPositionOpen( testLocation ) ) {
          // We found a location that is open.
          openLocation = testLocation;
          found = true;
        }
        else {
          positionInLayer++;
          if ( positionInLayer >= numParticlesInLayer ) {
            // Move to the next layer.
            row++;
            positionInLayer = 0;
            numParticlesInLayer--;
            offsetFromBucketEdge += this._sphereRadius;
            if ( numParticlesInLayer === 0 ) {
              // This algorithm doesn't handle the situation where
              // more particles are added than can be stacked into
              // a pyramid of the needed size, but so far it hasn't
              // needed to.  If this requirement changes, the
              // algorithm will need to change too.
              numParticlesInLayer = 1;
              offsetFromBucketEdge -= this._sphereRadius;
            }
          }
        }
      }
      return openLocation;
    },

    // @private
    getLayerForYPosition: function( yPosition ) {
      return Math.abs( Math.round( ( yPosition - ( this.position.y + this._verticalParticleOffset ) ) / ( this._sphereRadius * 2 * 0.866 ) ) );
    },

    /*
     * Get the nearest open location to the provided current location.  This is used for particle stacking.
     *
     * @param {Vector2} position
     * @return {Vector2}
     * @private
     */
    getNearestOpenLocation: function( position ) {
      // Determine the highest occupied layer.  The bottom layer is 0.
      var highestOccupiedLayer = 0;
      var self = this;
      _.each( this._particles, function( particle ) {
        var layer = self.getLayerForYPosition( particle.destination.y );
        if ( layer > highestOccupiedLayer ) {
          highestOccupiedLayer = layer;
        }
      } );

      // Make a list of all open locations in the occupied layers.
      var openLocations = [];
      var usableWidth = this.size.width * this._usableWidthProportion - 2 * this._sphereRadius;
      var offsetFromBucketEdge = ( this.size.width - usableWidth ) / 2 + this._sphereRadius;
      var numParticlesInLayer = Math.floor( usableWidth / ( this._sphereRadius * 2 ) );

      // Loop, searching for open positions in the particle stack.
      for ( var layer = 0; layer <= highestOccupiedLayer + 1; layer++ ) {

        // Add all open locations in the current layer.
        for ( var positionInLayer = 0; positionInLayer < numParticlesInLayer; positionInLayer++ ) {
          var testPosition = new Vector2( this.position.x - this.size.width / 2 + offsetFromBucketEdge + positionInLayer * 2 * this._sphereRadius,
            this.getYPositionForLayer( layer ) );
          if ( this.isPositionOpen( testPosition ) ) {

            // We found a location that is unoccupied.
            if ( layer === 0 || this.countSupportingParticles( testPosition ) === 2 ) {
              // This is a valid open location.
              openLocations.push( testPosition );
            }
          }
        }

        // Adjust variables for the next layer.
        numParticlesInLayer--;
        offsetFromBucketEdge += this._sphereRadius;
        if ( numParticlesInLayer === 0 ) {
          // If the stacking pyramid is full, meaning that there are
          // no locations that are open within it, this algorithm
          // classifies the locations directly above the top of the
          // pyramid as being open.  This would result in a stack
          // of particles with a pyramid base.  So far, this hasn't
          // been a problem, but this limitation may limit
          // reusability of this algorithm.
          numParticlesInLayer = 1;
          offsetFromBucketEdge -= this._sphereRadius;
        }
      }

      // Find the closest open location to the provided current location.
      // Only the X-component is used for this determination, because if
      // the Y-component is used the particles often appear to fall sideways
      // when released above the bucket, which just looks weird.
      var closestOpenLocation = openLocations[ 0 ] || Vector2.ZERO;

      _.each( openLocations, function( location ) {
        if ( location.distance( position ) < closestOpenLocation.distance( position ) ) {
          // This location is closer.
          closestOpenLocation = location;
        }
      } );
      return closestOpenLocation;
    },

    // @private
    getYPositionForLayer: function( layer ) {
      return this.position.y + this._verticalParticleOffset + layer * this._sphereRadius * 2 * 0.866;
    },

    /*
     * Determine whether a particle is 'dangling', i.e. hanging above an open
     * space in the stack of particles.  Dangling particles should fall.
     * @private
     */
    isDangling: function( particle ) {
      var onBottomRow = particle.destination.y === this.position.y + this._verticalParticleOffset;
      return !onBottomRow && this.countSupportingParticles( particle.destination ) < 2;
    },

    // @private
    countSupportingParticles: function( position ) {
      var count = 0;
      for ( var i = 0; i < this._particles.length; i++ ) {
        var p = this._particles[ i ];
        if ( p.destination.y < position.y && // Must be in a lower layer
             p.destination.distance( position ) < this._sphereRadius * 3 ) {
          // Must be a supporting particle.
          count++;
        }
      }
      return count;
    },

    // @private
    relayoutBucketParticles: function() {
      var particleMoved;
      do {
        for ( var i = 0; i < this._particles.length; i++ ) {
          particleMoved = false;
          var particle = this._particles[ i ];
          if ( this.isDangling( particle ) ) {
            particle.destination = this.getNearestOpenLocation( particle.destination );
            particleMoved = true;
            break;
          }
        }
      } while ( particleMoved );
    }

  } );

  return SphereBucket;
} );
<|endoftext|>


<commit_before>require("ember-data/system/model/states");

var get = Ember.get, set = Ember.set, getPath = Ember.getPath, none = Ember.none;

var retrieveFromCurrentState = Ember.computed(function(key) {
  return get(getPath(this, 'stateManager.currentState'), key);
}).property('stateManager.currentState').cacheable();

// This object is a regular JS object for performance. It is only
// used internally for bookkeeping purposes.
var DataProxy = function(record) {
  this.record = record;
  this.unsavedData = {};
  this.associations = {};
};

DataProxy.prototype = {
  get: function(key) { return Ember.get(this, key); },
  set: function(key, value) { return Ember.set(this, key, value); },

  setAssociation: function(key, value) {
    this.associations[key] = value;
  },

  savedData: function() {
    var savedData = this._savedData;
    if (savedData) { return savedData; }

    var record = this.record,
        clientId = get(record, 'clientId'),
        store = get(record, 'store');

    if (store) {
      savedData = store.dataForRecord(record);
      this._savedData = savedData;
      return savedData;
    }
  },

  unknownProperty: function(key) {
    var unsavedData = this.unsavedData,
        associations = this.associations,
        savedData = this.savedData(),
        store;

    var value = unsavedData[key], association;

    // if this is a belongsTo association, this will
    // be a clientId.
    association = associations[key];

    if (association !== undefined) {
      store = get(this.record, 'store');
      return store.clientIdToId[association];
    }

    if (savedData && value === undefined) {
      value = savedData[key];
    }

    return value;
  },

  setUnknownProperty: function(key, value) {
    var record = this.record,
        unsavedData = this.unsavedData;

    unsavedData[key] = value;

    record.hashWasUpdated();

    return value;
  },

  commit: function() {
    var record = this.record;

    var unsavedData = this.unsavedData;
    var savedData = this.savedData();

    for (var prop in unsavedData) {
      if (unsavedData.hasOwnProperty(prop)) {
        savedData[prop] = unsavedData[prop];
        delete unsavedData[prop];
      }
    }

    record.notifyPropertyChange('data');
  },

  rollback: function() {
    this.unsavedData = {};
  },

  adapterDidUpdate: function(data) {
    this.unsavedData = {};
  }
};

DS.Model = Ember.Object.extend({
  isLoaded: retrieveFromCurrentState,
  isDirty: retrieveFromCurrentState,
  isSaving: retrieveFromCurrentState,
  isDeleted: retrieveFromCurrentState,
  isError: retrieveFromCurrentState,
  isNew: retrieveFromCurrentState,
  isPending: retrieveFromCurrentState,
  isValid: retrieveFromCurrentState,

  clientId: null,
  transaction: null,
  stateManager: null,
  pendingQueue: null,
  errors: null,

  // because unknownProperty is used, any internal property
  // must be initialized here.
  primaryKey: 'id',
  id: Ember.computed(function(key, value) {
    var primaryKey = get(this, 'primaryKey'),
        data = get(this, 'data');

    if (arguments.length === 2) {
      set(data, primaryKey, value);
      return value;
    }

    return data && get(data, primaryKey);
  }).property('primaryKey', 'data'),

  // The following methods are callbacks invoked by `getJSON`. You
  // can override one of the callbacks to override specific behavior,
  // or getJSON itself.
  //
  // If you override getJSON, you can invoke these callbacks manually
  // to get the default behavior.

  /**
    Add the record's primary key to the JSON hash.

    The default implementation uses the record's specified `primaryKey`
    and the `id` computed property, which are passed in as parameters.

    @param {Object} json the JSON hash being built
    @param {Number|String} id the record's id
    @param {String} key the primaryKey for the record
  */
  addIdToJSON: function(json, id, key) {
    if (id) { json[key] = id; }
  },

  /**
    Add the attributes' current values to the JSON hash.

    The default implementation gets the current value of each
    attribute from the `data`, and uses a `defaultValue` if
    specified in the `DS.attr` definition.

    @param {Object} json the JSON hash being build
    @param {Ember.Map} attributes a Map of attributes
    @param {DataProxy} data the record's data, accessed with `get` and `set`.
  */
  addAttributesToJSON: function(json, attributes, data) {
    attributes.forEach(function(name, meta) {
      var key = meta.key(this.constructor),
          value = get(data, key);

      if (value === undefined) {
        value = meta.options.defaultValue;
      }

      json[key] = value;
    }, this);
  },

  /**
    Add the value of a `hasMany` association to the JSON hash.

    The default implementation honors the `embedded` option
    passed to `DS.hasMany`. If embedded, `toJSON` is recursively
    called on the child records. If not, the `id` of each
    record is added.

    Note that if a record is not embedded and does not
    yet have an `id` (usually provided by the server), it
    will not be included in the output.

    @param {Object} json the JSON hash being built
    @param {DataProxy} data the record's data, accessed with `get` and `set`.
    @param {Object} meta information about the association
    @param {Object} options options passed to `toJSON`
  */
  addHasManyToJSON: function(json, data, meta, options) {
    var key = meta.key,
        manyArray = get(this, key),
        records = [],
        clientId, id;

    if (meta.options.embedded) {
      // TODO: Avoid materializing embedded hashes if possible
      manyArray.forEach(function(record) {
        records.push(record.toJSON(options));
      });
    } else {
      var clientIds = get(manyArray, 'content');

      for (var i=0, l=clientIds.length; i<l; i++) {
        clientId = clientIds[i];
        id = get(this, 'store').clientIdToId[clientId];

        if (id !== undefined) {
          records.push(id);
        }
      }
    }

    json[key] = records;
  },

  /**
    Add the value of a `belongsTo` association to the JSON hash.

    The default implementation always includes the `id`.

    @param {Object} json the JSON hash being built
    @param {DataProxy} data the record's data, accessed with `get` and `set`.
    @param {Object} meta information about the association
    @param {Object} options options passed to `toJSON`
  */
  addBelongsToToJSON: function(json, data, meta, options) {
    var key = meta.key, value, id;

    if (options.embedded) {
      key = options.key || get(this, 'namingConvention').keyToJSONKey(key);
      value = get(data.record, key);
      json[key] = value ? value.toJSON(options) : null;
    } else {
      key = options.key || get(this, 'namingConvention').foreignKey(key);
      id = data.get(key);
      json[key] = none(id) ? null : id;
    }
  },
  /**
    Create a JSON representation of the record, including its `id`,
    attributes and associations. Honor any settings defined on the
    attributes or associations (such as `embedded` or `key`).
  */
  toJSON: function(options) {
    var data = get(this, 'data'),
        result = {},
        type = this.constructor,
        attributes = get(type, 'attributes'),
        primaryKey = get(this, 'primaryKey'),
        id = get(this, 'id'),
        store = get(this, 'store'),
        associations;

    options = options || {};

    // delegate to `addIdToJSON` callback
    this.addIdToJSON(result, id, primaryKey);

    // delegate to `addAttributesToJSON` callback
    this.addAttributesToJSON(result, attributes, data);

    associations = get(type, 'associationsByName');

    // add associations, delegating to `addHasManyToJSON` and
    // `addBelongsToToJSON`.
    associations.forEach(function(key, meta) {
      if (options.associations && meta.kind === 'hasMany') {
        this.addHasManyToJSON(result, data, meta, options);
      } else if (meta.kind === 'belongsTo') {
        this.addBelongsToToJSON(result, data, meta, options);
      }
    }, this);

    return result;
  },

  data: Ember.computed(function() {
    return new DataProxy(this);
  }).cacheable(),

  didLoad: Ember.K,
  didUpdate: Ember.K,
  didCreate: Ember.K,

  init: function() {
    var stateManager = DS.StateManager.create({
      model: this
    });

    set(this, 'pendingQueue', {});

    set(this, 'stateManager', stateManager);
    stateManager.goToState('empty');
  },

  destroy: function() {
    if (!get(this, 'isDeleted')) {
      this.deleteRecord();
    }
    this._super();
  },

  send: function(name, context) {
    return get(this, 'stateManager').send(name, context);
  },

  withTransaction: function(fn) {
    var transaction = get(this, 'transaction');
    if (transaction) { fn(transaction); }
  },

  setProperty: function(key, value) {
    this.send('setProperty', { key: key, value: value });
  },

  deleteRecord: function() {
    this.send('deleteRecord');
  },

  waitingOn: function(record) {
    this.send('waitingOn', record);
  },

  notifyHashWasUpdated: function() {
    var store = get(this, 'store');
    if (store) {
      store.hashWasUpdated(this.constructor, get(this, 'clientId'), this);
    }
  },

  unknownProperty: function(key) {
    var data = get(this, 'data');

    if (data && key in data) {
      ember_assert("You attempted to access the " + key + " property on a model without defining an attribute.", false);
    }
  },

  setUnknownProperty: function(key, value) {
    var data = get(this, 'data');

    if (data && key in data) {
      ember_assert("You attempted to set the " + key + " property on a model without defining an attribute.", false);
    } else {
      return this._super(key, value);
    }
  },

  namingConvention: {
    keyToJSONKey: function(key) {
      // TODO: Strip off `is` from the front. Example: `isHipster` becomes `hipster`
      return Ember.String.decamelize(key);
    },

    foreignKey: function(key) {
      return Ember.String.decamelize(key) + '_id';
    }
  },

  /** @private */
  hashWasUpdated: function() {
    // At the end of the run loop, notify model arrays that
    // this record has changed so they can re-evaluate its contents
    // to determine membership.
    Ember.run.once(this, this.notifyHashWasUpdated);
  }
});

// Helper function to generate store aliases.
// This returns a function that invokes the named alias
// on the default store, but injects the class as the
// first parameter.
var storeAlias = function(methodName) {
  return function() {
    var store = get(DS, 'defaultStore'),
        args = [].slice.call(arguments);

    args.unshift(this);
    return store[methodName].apply(store, args);
  };
};

DS.Model.reopenClass({
  find: storeAlias('find'),
  filter: storeAlias('filter'),

  _create: DS.Model.create,

  create: function() {
    throw new Ember.Error("You should not call `create` on a model. Instead, call `createRecord` with the attributes you would like to set.");
  },

  createRecord: storeAlias('createRecord')
});
<commit_msg>Updates commets to reflect the code<commit_after>require("ember-data/system/model/states");

var get = Ember.get, set = Ember.set, getPath = Ember.getPath, none = Ember.none;

var retrieveFromCurrentState = Ember.computed(function(key) {
  return get(getPath(this, 'stateManager.currentState'), key);
}).property('stateManager.currentState').cacheable();

// This object is a regular JS object for performance. It is only
// used internally for bookkeeping purposes.
var DataProxy = function(record) {
  this.record = record;
  this.unsavedData = {};
  this.associations = {};
};

DataProxy.prototype = {
  get: function(key) { return Ember.get(this, key); },
  set: function(key, value) { return Ember.set(this, key, value); },

  setAssociation: function(key, value) {
    this.associations[key] = value;
  },

  savedData: function() {
    var savedData = this._savedData;
    if (savedData) { return savedData; }

    var record = this.record,
        clientId = get(record, 'clientId'),
        store = get(record, 'store');

    if (store) {
      savedData = store.dataForRecord(record);
      this._savedData = savedData;
      return savedData;
    }
  },

  unknownProperty: function(key) {
    var unsavedData = this.unsavedData,
        associations = this.associations,
        savedData = this.savedData(),
        store;

    var value = unsavedData[key], association;

    // if this is a belongsTo association, this will
    // be a clientId.
    association = associations[key];

    if (association !== undefined) {
      store = get(this.record, 'store');
      return store.clientIdToId[association];
    }

    if (savedData && value === undefined) {
      value = savedData[key];
    }

    return value;
  },

  setUnknownProperty: function(key, value) {
    var record = this.record,
        unsavedData = this.unsavedData;

    unsavedData[key] = value;

    record.hashWasUpdated();

    return value;
  },

  commit: function() {
    var record = this.record;

    var unsavedData = this.unsavedData;
    var savedData = this.savedData();

    for (var prop in unsavedData) {
      if (unsavedData.hasOwnProperty(prop)) {
        savedData[prop] = unsavedData[prop];
        delete unsavedData[prop];
      }
    }

    record.notifyPropertyChange('data');
  },

  rollback: function() {
    this.unsavedData = {};
  },

  adapterDidUpdate: function(data) {
    this.unsavedData = {};
  }
};

DS.Model = Ember.Object.extend({
  isLoaded: retrieveFromCurrentState,
  isDirty: retrieveFromCurrentState,
  isSaving: retrieveFromCurrentState,
  isDeleted: retrieveFromCurrentState,
  isError: retrieveFromCurrentState,
  isNew: retrieveFromCurrentState,
  isPending: retrieveFromCurrentState,
  isValid: retrieveFromCurrentState,

  clientId: null,
  transaction: null,
  stateManager: null,
  pendingQueue: null,
  errors: null,

  // because unknownProperty is used, any internal property
  // must be initialized here.
  primaryKey: 'id',
  id: Ember.computed(function(key, value) {
    var primaryKey = get(this, 'primaryKey'),
        data = get(this, 'data');

    if (arguments.length === 2) {
      set(data, primaryKey, value);
      return value;
    }

    return data && get(data, primaryKey);
  }).property('primaryKey', 'data'),

  // The following methods are callbacks invoked by `toJSON`. You
  // can override one of the callbacks to override specific behavior,
  // or toJSON itself.
  //
  // If you override toJSON, you can invoke these callbacks manually
  // to get the default behavior.

  /**
    Add the record's primary key to the JSON hash.

    The default implementation uses the record's specified `primaryKey`
    and the `id` computed property, which are passed in as parameters.

    @param {Object} json the JSON hash being built
    @param {Number|String} id the record's id
    @param {String} key the primaryKey for the record
  */
  addIdToJSON: function(json, id, key) {
    if (id) { json[key] = id; }
  },

  /**
    Add the attributes' current values to the JSON hash.

    The default implementation gets the current value of each
    attribute from the `data`, and uses a `defaultValue` if
    specified in the `DS.attr` definition.

    @param {Object} json the JSON hash being build
    @param {Ember.Map} attributes a Map of attributes
    @param {DataProxy} data the record's data, accessed with `get` and `set`.
  */
  addAttributesToJSON: function(json, attributes, data) {
    attributes.forEach(function(name, meta) {
      var key = meta.key(this.constructor),
          value = get(data, key);

      if (value === undefined) {
        value = meta.options.defaultValue;
      }

      json[key] = value;
    }, this);
  },

  /**
    Add the value of a `hasMany` association to the JSON hash.

    The default implementation honors the `embedded` option
    passed to `DS.hasMany`. If embedded, `toJSON` is recursively
    called on the child records. If not, the `id` of each
    record is added.

    Note that if a record is not embedded and does not
    yet have an `id` (usually provided by the server), it
    will not be included in the output.

    @param {Object} json the JSON hash being built
    @param {DataProxy} data the record's data, accessed with `get` and `set`.
    @param {Object} meta information about the association
    @param {Object} options options passed to `toJSON`
  */
  addHasManyToJSON: function(json, data, meta, options) {
    var key = meta.key,
        manyArray = get(this, key),
        records = [],
        clientId, id;

    if (meta.options.embedded) {
      // TODO: Avoid materializing embedded hashes if possible
      manyArray.forEach(function(record) {
        records.push(record.toJSON(options));
      });
    } else {
      var clientIds = get(manyArray, 'content');

      for (var i=0, l=clientIds.length; i<l; i++) {
        clientId = clientIds[i];
        id = get(this, 'store').clientIdToId[clientId];

        if (id !== undefined) {
          records.push(id);
        }
      }
    }

    json[key] = records;
  },

  /**
    Add the value of a `belongsTo` association to the JSON hash.

    The default implementation always includes the `id`.

    @param {Object} json the JSON hash being built
    @param {DataProxy} data the record's data, accessed with `get` and `set`.
    @param {Object} meta information about the association
    @param {Object} options options passed to `toJSON`
  */
  addBelongsToToJSON: function(json, data, meta, options) {
    var key = meta.key, value, id;

    if (options.embedded) {
      key = options.key || get(this, 'namingConvention').keyToJSONKey(key);
      value = get(data.record, key);
      json[key] = value ? value.toJSON(options) : null;
    } else {
      key = options.key || get(this, 'namingConvention').foreignKey(key);
      id = data.get(key);
      json[key] = none(id) ? null : id;
    }
  },
  /**
    Create a JSON representation of the record, including its `id`,
    attributes and associations. Honor any settings defined on the
    attributes or associations (such as `embedded` or `key`).
  */
  toJSON: function(options) {
    var data = get(this, 'data'),
        result = {},
        type = this.constructor,
        attributes = get(type, 'attributes'),
        primaryKey = get(this, 'primaryKey'),
        id = get(this, 'id'),
        store = get(this, 'store'),
        associations;

    options = options || {};

    // delegate to `addIdToJSON` callback
    this.addIdToJSON(result, id, primaryKey);

    // delegate to `addAttributesToJSON` callback
    this.addAttributesToJSON(result, attributes, data);

    associations = get(type, 'associationsByName');

    // add associations, delegating to `addHasManyToJSON` and
    // `addBelongsToToJSON`.
    associations.forEach(function(key, meta) {
      if (options.associations && meta.kind === 'hasMany') {
        this.addHasManyToJSON(result, data, meta, options);
      } else if (meta.kind === 'belongsTo') {
        this.addBelongsToToJSON(result, data, meta, options);
      }
    }, this);

    return result;
  },

  data: Ember.computed(function() {
    return new DataProxy(this);
  }).cacheable(),

  didLoad: Ember.K,
  didUpdate: Ember.K,
  didCreate: Ember.K,

  init: function() {
    var stateManager = DS.StateManager.create({
      model: this
    });

    set(this, 'pendingQueue', {});

    set(this, 'stateManager', stateManager);
    stateManager.goToState('empty');
  },

  destroy: function() {
    if (!get(this, 'isDeleted')) {
      this.deleteRecord();
    }
    this._super();
  },

  send: function(name, context) {
    return get(this, 'stateManager').send(name, context);
  },

  withTransaction: function(fn) {
    var transaction = get(this, 'transaction');
    if (transaction) { fn(transaction); }
  },

  setProperty: function(key, value) {
    this.send('setProperty', { key: key, value: value });
  },

  deleteRecord: function() {
    this.send('deleteRecord');
  },

  waitingOn: function(record) {
    this.send('waitingOn', record);
  },

  notifyHashWasUpdated: function() {
    var store = get(this, 'store');
    if (store) {
      store.hashWasUpdated(this.constructor, get(this, 'clientId'), this);
    }
  },

  unknownProperty: function(key) {
    var data = get(this, 'data');

    if (data && key in data) {
      ember_assert("You attempted to access the " + key + " property on a model without defining an attribute.", false);
    }
  },

  setUnknownProperty: function(key, value) {
    var data = get(this, 'data');

    if (data && key in data) {
      ember_assert("You attempted to set the " + key + " property on a model without defining an attribute.", false);
    } else {
      return this._super(key, value);
    }
  },

  namingConvention: {
    keyToJSONKey: function(key) {
      // TODO: Strip off `is` from the front. Example: `isHipster` becomes `hipster`
      return Ember.String.decamelize(key);
    },

    foreignKey: function(key) {
      return Ember.String.decamelize(key) + '_id';
    }
  },

  /** @private */
  hashWasUpdated: function() {
    // At the end of the run loop, notify model arrays that
    // this record has changed so they can re-evaluate its contents
    // to determine membership.
    Ember.run.once(this, this.notifyHashWasUpdated);
  }
});

// Helper function to generate store aliases.
// This returns a function that invokes the named alias
// on the default store, but injects the class as the
// first parameter.
var storeAlias = function(methodName) {
  return function() {
    var store = get(DS, 'defaultStore'),
        args = [].slice.call(arguments);

    args.unshift(this);
    return store[methodName].apply(store, args);
  };
};

DS.Model.reopenClass({
  find: storeAlias('find'),
  filter: storeAlias('filter'),

  _create: DS.Model.create,

  create: function() {
    throw new Ember.Error("You should not call `create` on a model. Instead, call `createRecord` with the attributes you would like to set.");
  },

  createRecord: storeAlias('createRecord')
});
<|endoftext|>


<commit_before>'use strict';

module.exports = {
	db: process.env.MONGOHQ_URL || process.env.MONGOLAB_URI || 'mongodb://' + (process.env.DB_1_PORT_27017_TCP_ADDR || 'localhost') + '/fileupload',
	facebook: {
		clientID: process.env.FACEBOOK_ID || 'APP_ID',
		clientSecret: process.env.FACEBOOK_SECRET || 'APP_SECRET',
		callbackURL: '/auth/facebook/callback'
	},
	twitter: {
		clientID: process.env.TWITTER_KEY || 'CONSUMER_KEY',
		clientSecret: process.env.TWITTER_SECRET || 'CONSUMER_SECRET',
		callbackURL: '/auth/twitter/callback'
	},
	google: {
		clientID: process.env.GOOGLE_ID || 'APP_ID',
		clientSecret: process.env.GOOGLE_SECRET || 'APP_SECRET',
		callbackURL: '/auth/google/callback'
	},
	linkedin: {
		clientID: process.env.LINKEDIN_ID || 'APP_ID',
		clientSecret: process.env.LINKEDIN_SECRET || 'APP_SECRET',
		callbackURL: '/auth/linkedin/callback'
	},
	github: {
		clientID: process.env.GITHUB_ID || 'APP_ID',
		clientSecret: process.env.GITHUB_SECRET || 'APP_SECRET',
		callbackURL: '/auth/github/callback'
	},
	mailer: {
		from: process.env.MAILER_FROM || 'MAILER_FROM',
		options: {
			service: process.env.MAILER_SERVICE_PROVIDER || 'MAILER_SERVICE_PROVIDER',
			auth: {
				user: process.env.MAILER_EMAIL_ID || 'MAILER_EMAIL_ID',
				pass: process.env.MAILER_PASSWORD || 'MAILER_PASSWORD'
			}
		}
	}
};
<commit_msg>db ENV<commit_after>'use strict';

module.exports = {
	db: process.env.MONGO_URI || process.env.MONGOLAB_URI || 'mongodb://' + (process.env.DB_1_PORT_27017_TCP_ADDR || 'localhost') + '/fileupload',
	facebook: {
		clientID: process.env.FACEBOOK_ID || 'APP_ID',
		clientSecret: process.env.FACEBOOK_SECRET || 'APP_SECRET',
		callbackURL: '/auth/facebook/callback'
	},
	twitter: {
		clientID: process.env.TWITTER_KEY || 'CONSUMER_KEY',
		clientSecret: process.env.TWITTER_SECRET || 'CONSUMER_SECRET',
		callbackURL: '/auth/twitter/callback'
	},
	google: {
		clientID: process.env.GOOGLE_ID || 'APP_ID',
		clientSecret: process.env.GOOGLE_SECRET || 'APP_SECRET',
		callbackURL: '/auth/google/callback'
	},
	linkedin: {
		clientID: process.env.LINKEDIN_ID || 'APP_ID',
		clientSecret: process.env.LINKEDIN_SECRET || 'APP_SECRET',
		callbackURL: '/auth/linkedin/callback'
	},
	github: {
		clientID: process.env.GITHUB_ID || 'APP_ID',
		clientSecret: process.env.GITHUB_SECRET || 'APP_SECRET',
		callbackURL: '/auth/github/callback'
	},
	mailer: {
		from: process.env.MAILER_FROM || 'MAILER_FROM',
		options: {
			service: process.env.MAILER_SERVICE_PROVIDER || 'MAILER_SERVICE_PROVIDER',
			auth: {
				user: process.env.MAILER_EMAIL_ID || 'MAILER_EMAIL_ID',
				pass: process.env.MAILER_PASSWORD || 'MAILER_PASSWORD'
			}
		}
	}
};
<|endoftext|>


<commit_before>class FormWizard {
    static create(params) {
        console.log('FormWizard.create', params);
        switch (params.model.database.getClassName()) {
            case 'MySqlDatabase'     : return new MySqlFormWizard(params);
            case 'PostgreSqlDatabase': return new PostgreSqlFormWizard(params);
            default: throw new Error(`unknown database class: ${params.model.database.getClassName()}`);
        }
    }

    constructor(params) {
        console.log('FormWizard.constructor', params);
        this.params        = params;
        this.model         = params.model;
        this.databaseName  = params.model.database.getName();
        this.tableName     = params.model.getName();
        this.tableColumns  = Object.keys(params.model.data.columns).map(name => params.model.data.columns[name]['@attributes']);
    }

    getDataSources() {
        return {
            default: {
                class     : 'SqlDataSource',
                name      : 'default',
                database  : this.databaseName,
                table     : this.tableName,
                limit     : this.params.className === 'TableForm' ? '100' : '',
                countQuery   : this.getCountQuery(),
                singleQuery  : this.getSingleQuery(),
                multipleQuery: this.getMultipleQuery()
            }
        };
    }

    getFieldClass(column) {
        if (column.type === 'date') return 'DatePickerField';
        if (this.params.className === 'RowForm' && column.dbType === 'text') return 'TextAreaField';
        if (column.type === 'boolean') return 'CheckBoxField';
        return 'TextBoxField';
    }

    getField(column) {
        // console.log('FormWizard.getField', column);
        let field = {
            class: this.getFieldClass(column),
            name : column.name
        };
        if (column.caption) {
            field.caption = column.caption;
        }
        if (column.key === 'true') {
            if (column.auto === 'false') {
                field.notNull = 'true';
            }
        } else {
            if (column.nullable === 'false') {
                field.notNull = 'true';
                field.readOnly = 'false';
            }
        }
        if (column.auto === 'true') {
            field.readOnly = 'true';
        }
        return field;
    }

    getFields() {
        let fields = {};
        this.getColumns().forEach(column => {
            fields[column.name] = this.getField(column);
        });
        /*for (let i = 0; i < this.tableColumns.length; i++) {
            const column = this.tableColumns[i];
            fields[column.name] = this.getField(column);
        }*/
        return fields;
    }

    getColumns() {
        return this.tableColumns.filter(column => {
            if (this.params.className === 'TableForm') {
                if (column.dbType === 'text') return false;
                if (column.dbType === 'bytea') return false;
            }
            return true;
        });
    }

    getFormParams() {
        return {
            name       : this.params.formName,
            caption    : this.params.formCaption,
            class      : this.params.className,
            dataSources: this.getDataSources(),
            fields     : this.getFields()
        };
    }
}
<commit_msg>TextAreaField for json column in RowForm<commit_after>class FormWizard {
    static create(params) {
        console.log('FormWizard.create', params);
        switch (params.model.database.getClassName()) {
            case 'MySqlDatabase'     : return new MySqlFormWizard(params);
            case 'PostgreSqlDatabase': return new PostgreSqlFormWizard(params);
            default: throw new Error(`unknown database class: ${params.model.database.getClassName()}`);
        }
    }

    constructor(params) {
        console.log('FormWizard.constructor', params);
        this.params        = params;
        this.model         = params.model;
        this.databaseName  = params.model.database.getName();
        this.tableName     = params.model.getName();
        this.tableColumns  = Object.keys(params.model.data.columns).map(name => params.model.data.columns[name]['@attributes']);
    }

    getDataSources() {
        return {
            default: {
                class     : 'SqlDataSource',
                name      : 'default',
                database  : this.databaseName,
                table     : this.tableName,
                limit     : this.params.className === 'TableForm' ? '100' : '',
                countQuery   : this.getCountQuery(),
                singleQuery  : this.getSingleQuery(),
                multipleQuery: this.getMultipleQuery()
            }
        };
    }

    getFieldClass(column) {
        if (column.type === 'date') return 'DatePickerField';
        if (column.type === 'boolean') return 'CheckBoxField';
        if (this.params.className === 'RowForm') {
            if (column.dbType === 'text') {
                return 'TextAreaField';
            }
            if (column.dbType === 'json') {
                return 'TextAreaField';
            }
        }
        return 'TextBoxField';
    }

    getField(column) {
        // console.log('FormWizard.getField', column);
        let field = {
            class: this.getFieldClass(column),
            name : column.name
        };
        if (column.caption) {
            field.caption = column.caption;
        }
        if (column.key === 'true') {
            if (column.auto === 'false') {
                field.notNull = 'true';
            }
        } else {
            if (column.nullable === 'false') {
                field.notNull = 'true';
                field.readOnly = 'false';
            }
        }
        if (column.auto === 'true') {
            field.readOnly = 'true';
        }
        return field;
    }

    getFields() {
        let fields = {};
        this.getColumns().forEach(column => {
            fields[column.name] = this.getField(column);
        });
        /*for (let i = 0; i < this.tableColumns.length; i++) {
            const column = this.tableColumns[i];
            fields[column.name] = this.getField(column);
        }*/
        return fields;
    }

    getColumns() {
        return this.tableColumns.filter(column => {
            if (this.params.className === 'TableForm') {
                if (column.dbType === 'text') return false;
                if (column.dbType === 'bytea') return false;
            }
            return true;
        });
    }

    getFormParams() {
        return {
            name       : this.params.formName,
            caption    : this.params.formCaption,
            class      : this.params.className,
            dataSources: this.getDataSources(),
            fields     : this.getFields()
        };
    }
}
<|endoftext|>