<commit_before>////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////

'use strict';

const fs = require('fs-extra');
const path = require('path');
const os = require('os');
const child_process = require('child_process');
const fetch = require('node-fetch');
const ini = require('ini');
const decompress = require('decompress');

const LOCKFILE_NAME = 'download-realm.lock';

function exec() {
    const args = Array.from(arguments);
    return new Promise((resolve, reject) => {
        function callback(error, stdout, stderr) {
            if (error) {
                reject(error);
            } else {
                resolve(stdout.trim());
            }
        }
        args.push(callback);
        child_process.exec.apply(null, args);
    });
}

function printProgress(input, totalBytes, archive) {
    const ProgressBar = require('progress');
    const StreamCounter = require('stream-counter');

    const message = `Downloading ${archive} [:bar] (:ratek)`;
    const bar = new ProgressBar(message, {
       complete: '=',
       incomplete: ' ',
       width: process.stdout.columns - message.length,
       total: totalBytes / 1024
     });

     input.pipe(new StreamCounter()).on('progress', function() {
         bar.tick((this.bytes / 1024) - bar.curr);
     });
}

function download(serverFolder, archive, destination) {
    const url = `https://static.realm.io/downloads/${serverFolder}/${archive}`;
    console.log(`Download url: ${url}`);
    return fetch(url).then((response) => {
        if (response.status !== 200) {
            throw new Error(`Error downloading ${url} - received status ${response.status} ${response.statusText}`);
        }

        const lastModified = new Date(response.headers.get('Last-Modified'));
        return fs.exists(destination)
                 .then(exists => {
                     if (!exists) {
                         return saveFile();
                     } else {
                         return fs.stat(destination)
                                  .then(stat => {
                                      if (stat.mtime.getTime() !== lastModified.getTime()) {
                                          return saveFile();
                                      }
                         })
                     }
        });

        function saveFile() {
            if (process.stdout.isTTY) {
                printProgress(response.body, parseInt(response.headers.get('Content-Length')), archive);
            } else {
                console.log(`Downloading ${archive}`);
            }
            return new Promise((resolve) => {
                const file = fs.createWriteStream(destination);
                response.body.pipe(file).once('finish', () => file.close(resolve));
            }).then(() => fs.utimes(destination, lastModified, lastModified));
        }
    });
}

function extract(downloadedArchive, targetFolder, archiveRootFolder) {
    console.log(`Extracting ${path.basename(downloadedArchive)} => ${targetFolder}`);
    if (!archiveRootFolder) {
        return decompress(downloadedArchive, targetFolder);
    } else {
        const tempExtractLocation = path.resolve(os.tmpdir(), path.basename(downloadedArchive, path.extname(downloadedArchive)));
        return decompress(downloadedArchive, tempExtractLocation)
               .then(() => fs.readdir(path.resolve(tempExtractLocation, archiveRootFolder)))
               .then(items => Promise.all(items.map(item => {
                   const source = path.resolve(tempExtractLocation, archiveRootFolder, item);
                   const target = path.resolve(targetFolder, item);
                   return fs.copy(source, target, { filter: n => path.extname(n) !== '.so' });
               })))
               .then(() => fs.remove(tempExtractLocation))
    }
}

function acquire(desired, target) {
    const corePath = desired.CORE_ARCHIVE && path.resolve(os.tmpdir(), desired.CORE_ARCHIVE);
    const syncPath = desired.SYNC_ARCHIVE && path.resolve(os.tmpdir(), desired.SYNC_ARCHIVE);

    return fs.emptyDir(target)
        .then(() => corePath && download(desired.CORE_SERVER_FOLDER, desired.CORE_ARCHIVE, corePath))
        .then(() => corePath && extract(corePath, target, desired.CORE_ARCHIVE_ROOT))
        .then(() => syncPath && download(desired.SYNC_SERVER_FOLDER, desired.SYNC_ARCHIVE, syncPath))
        .then(() => syncPath && extract(syncPath, target, desired.SYNC_ARCHIVE_ROOT))
        .then(() => writeLockfile(target, desired))
}

function getSyncCommitSha(version) {
  return exec(`git ls-remote git@github.com:realm/realm-sync.git --tags "v${version}^{}"`)
         .then(stdout => {
           if (!stdout) {
             return exec(`git ls-remote git@github.com:realm/realm-sync.git --tags "v${version}"`)
           } else {
             return stdout;
           }
         }).then(stdout => /([^\t]+)/.exec(stdout)[0]);
}

function getCoreRequirements(dependencies, options, required = {}) {
    required.CORE_SERVER_FOLDER = `core/v${dependencies.REALM_CORE_VERSION}`;
    let flavor = options.debug ? 'Debug' : 'Release';

    switch (options.platform) {
        case 'mac':
            required.CORE_SERVER_FOLDER += `/macos/${flavor}`;
            required.CORE_ARCHIVE = `realm-core-${flavor}-v${dependencies.REALM_CORE_VERSION}-Darwin-devel.tar.gz`;
            return Promise.resolve(required);
        case 'ios':
            flavor = flavor === 'Debug' ? 'MinSizeDebug' : flavor;
            required.CORE_SERVER_FOLDER += `/ios/${flavor}`;
            required.CORE_ARCHIVE = `realm-core-${flavor}-v${dependencies.REALM_CORE_VERSION}-iphoneos.tar.gz`;
            return Promise.resolve(required);
        case 'win': {
            if (!options.arch) throw new Error(`Specifying '--arch' is required for platform 'win'`);
            const arch = options.arch === 'ia32' ? 'Win32' : options.arch;
            required.CORE_SERVER_FOLDER += `/windows/${arch}/nouwp/${flavor}`;
            required.CORE_ARCHIVE = `realm-core-${flavor}-v${dependencies.REALM_CORE_VERSION}-Windows-${arch}-devel.tar.gz`;
            return Promise.resolve(required);
        }
        case 'linux':
            required.CORE_SERVER_FOLDER = 'core';
            required.CORE_ARCHIVE = `realm-core-${dependencies.REALM_CORE_VERSION}.tgz`;
            required.CORE_ARCHIVE_ROOT = `realm-core-${dependencies.REALM_CORE_VERSION}`;
            return Promise.resolve(required);
        default:
            return Promise.reject(new Error(`Unsupported core platform '${options.platform}'`));
    }
}

function getSyncRequirements(dependencies, options, required = {}) {
    required.SYNC_SERVER_FOLDER = 'sync';
    let flavor = options.debug ? 'Debug' : 'Release';

    switch (options.platform) {
        case 'mac':
            required.SYNC_ARCHIVE = `realm-sync-node-cocoa-${dependencies.REALM_SYNC_VERSION}.tar.gz`;
            required.SYNC_ARCHIVE_ROOT = `realm-sync-node-cocoa-${dependencies.REALM_SYNC_VERSION}`;
            return Promise.resolve(required);
        case 'ios':
            required.SYNC_ARCHIVE = `realm-sync-cocoa-${dependencies.REALM_SYNC_VERSION}.tar.gz`;
            required.SYNC_ARCHIVE_ROOT = `core`;
            return Promise.resolve(required);
        case 'win': {
            const arch = options.arch === 'ia32' ? 'Win32' : options.arch;
            required.SYNC_ARCHIVE = `realm-sync-${flavor}-v${dependencies.REALM_SYNC_VERSION}-Windows-${arch}-devel.tar.gz`;
            return getCoreRequirements(dependencies, options, required)
                .then(() => getSyncCommitSha(dependencies.REALM_SYNC_VERSION))
                .then(sha => {
                    required.SYNC_SERVER_FOLDER += `/sha-version/${sha}`;
                    return required;
                });
        }
        default:
            return Promise.reject(new Error(`Unsupported sync platform '${options.platform}'`));
    }
}

function writeLockfile(target, contents) {
    return fs.writeFile(path.resolve(target, LOCKFILE_NAME), ini.encode(contents));
}

function readLockfile(target) {
    try {
        return ini.parse(fs.readFileSync(path.resolve(target, LOCKFILE_NAME), 'utf8'));
    } catch (e) {
        return null;
    }
}

function shouldSkipAcquire(target, requirements, force) {
    if (force) {
        console.log('Skipping lockfile check as --force is enabled');
        return false;
    }

    const existingLockfile = readLockfile(target);

    if (!existingLockfile) {
        console.log('No lockfile found at the target, proceeding.');
        return false;
    }

    if (!Object.keys(requirements).every(key => existingLockfile[key] === requirements[key])) {
        console.log('Target directory has a differing lockfile, overwriting.');
        return false;
    }

    console.log('Matching lockfile already exists at target - nothing to do (use --force to override)');
    return true;
}

const optionDefinitions = [
    { name: 'platform', type: String, defaultOption: true },
    { name: 'arch', type: String },
    { name: 'sync', type: Boolean },
    { name: 'debug', type: Boolean },
    { name: 'force', type: Boolean },
];
const options = require('command-line-args')(optionDefinitions);
if (options.platform === '..\\win') {
    options.platform = 'win'; // handle gyp idiocy
}

const vendorDir = path.resolve(__dirname, '../vendor');

let realmDir = path.resolve(vendorDir, `realm-${options.platform}`);
if (options.arch) {
    realmDir += `-${options.arch}`;
}
if (options.debug) {
    realmDir += '-dbg'
}

const dependencies = ini.parse(fs.readFileSync(path.resolve(__dirname, '../dependencies.list'), 'utf8'));

(options.sync ? getSyncRequirements : getCoreRequirements)(dependencies, options)
    .then(requirements => {
        console.log('Resolved requirements:', requirements);
        if (!shouldSkipAcquire(realmDir, requirements, options.force)) {
            return acquire(requirements, realmDir)
        }
    })
    .then(() => console.log('Success'))
    .catch(error => {
        console.error(error);
        process.exit(1);
    });
<commit_msg>Download Linux tar.gz too<commit_after>////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////

'use strict';

const fs = require('fs-extra');
const path = require('path');
const os = require('os');
const child_process = require('child_process');
const fetch = require('node-fetch');
const ini = require('ini');
const decompress = require('decompress');

const LOCKFILE_NAME = 'download-realm.lock';

function exec() {
    const args = Array.from(arguments);
    return new Promise((resolve, reject) => {
        function callback(error, stdout, stderr) {
            if (error) {
                reject(error);
            } else {
                resolve(stdout.trim());
            }
        }
        args.push(callback);
        child_process.exec.apply(null, args);
    });
}

function printProgress(input, totalBytes, archive) {
    const ProgressBar = require('progress');
    const StreamCounter = require('stream-counter');

    const message = `Downloading ${archive} [:bar] (:ratek)`;
    const bar = new ProgressBar(message, {
       complete: '=',
       incomplete: ' ',
       width: process.stdout.columns - message.length,
       total: totalBytes / 1024
     });

     input.pipe(new StreamCounter()).on('progress', function() {
         bar.tick((this.bytes / 1024) - bar.curr);
     });
}

function download(serverFolder, archive, destination) {
    const url = `https://static.realm.io/downloads/${serverFolder}/${archive}`;
    console.log(`Download url: ${url}`);
    return fetch(url).then((response) => {
        if (response.status !== 200) {
            throw new Error(`Error downloading ${url} - received status ${response.status} ${response.statusText}`);
        }

        const lastModified = new Date(response.headers.get('Last-Modified'));
        return fs.exists(destination)
                 .then(exists => {
                     if (!exists) {
                         return saveFile();
                     } else {
                         return fs.stat(destination)
                                  .then(stat => {
                                      if (stat.mtime.getTime() !== lastModified.getTime()) {
                                          return saveFile();
                                      }
                         })
                     }
        });

        function saveFile() {
            if (process.stdout.isTTY) {
                printProgress(response.body, parseInt(response.headers.get('Content-Length')), archive);
            } else {
                console.log(`Downloading ${archive}`);
            }
            return new Promise((resolve) => {
                const file = fs.createWriteStream(destination);
                response.body.pipe(file).once('finish', () => file.close(resolve));
            }).then(() => fs.utimes(destination, lastModified, lastModified));
        }
    });
}

function extract(downloadedArchive, targetFolder, archiveRootFolder) {
    console.log(`Extracting ${path.basename(downloadedArchive)} => ${targetFolder}`);
    if (!archiveRootFolder) {
        return decompress(downloadedArchive, targetFolder);
    } else {
        const tempExtractLocation = path.resolve(os.tmpdir(), path.basename(downloadedArchive, path.extname(downloadedArchive)));
        return decompress(downloadedArchive, tempExtractLocation)
               .then(() => fs.readdir(path.resolve(tempExtractLocation, archiveRootFolder)))
               .then(items => Promise.all(items.map(item => {
                   const source = path.resolve(tempExtractLocation, archiveRootFolder, item);
                   const target = path.resolve(targetFolder, item);
                   return fs.copy(source, target, { filter: n => path.extname(n) !== '.so' });
               })))
               .then(() => fs.remove(tempExtractLocation))
    }
}

function acquire(desired, target) {
    const corePath = desired.CORE_ARCHIVE && path.resolve(os.tmpdir(), desired.CORE_ARCHIVE);
    const syncPath = desired.SYNC_ARCHIVE && path.resolve(os.tmpdir(), desired.SYNC_ARCHIVE);

    return fs.emptyDir(target)
        .then(() => corePath && download(desired.CORE_SERVER_FOLDER, desired.CORE_ARCHIVE, corePath))
        .then(() => corePath && extract(corePath, target, desired.CORE_ARCHIVE_ROOT))
        .then(() => syncPath && download(desired.SYNC_SERVER_FOLDER, desired.SYNC_ARCHIVE, syncPath))
        .then(() => syncPath && extract(syncPath, target, desired.SYNC_ARCHIVE_ROOT))
        .then(() => writeLockfile(target, desired))
}

function getSyncCommitSha(version) {
  return exec(`git ls-remote git@github.com:realm/realm-sync.git --tags "v${version}^{}"`)
         .then(stdout => {
           if (!stdout) {
             return exec(`git ls-remote git@github.com:realm/realm-sync.git --tags "v${version}"`)
           } else {
             return stdout;
           }
         }).then(stdout => /([^\t]+)/.exec(stdout)[0]);
}

function getCoreRequirements(dependencies, options, required = {}) {
    required.CORE_SERVER_FOLDER = `core/v${dependencies.REALM_CORE_VERSION}`;
    let flavor = options.debug ? 'Debug' : 'Release';

    switch (options.platform) {
        case 'mac':
            required.CORE_SERVER_FOLDER += `/macos/${flavor}`;
            required.CORE_ARCHIVE = `realm-core-${flavor}-v${dependencies.REALM_CORE_VERSION}-Darwin-devel.tar.gz`;
            return Promise.resolve(required);
        case 'ios':
            flavor = flavor === 'Debug' ? 'MinSizeDebug' : flavor;
            required.CORE_SERVER_FOLDER += `/ios/${flavor}`;
            required.CORE_ARCHIVE = `realm-core-${flavor}-v${dependencies.REALM_CORE_VERSION}-iphoneos.tar.gz`;
            return Promise.resolve(required);
        case 'win': {
            if (!options.arch) throw new Error(`Specifying '--arch' is required for platform 'win'`);
            const arch = options.arch === 'ia32' ? 'Win32' : options.arch;
            required.CORE_SERVER_FOLDER += `/windows/${arch}/nouwp/${flavor}`;
            required.CORE_ARCHIVE = `realm-core-${flavor}-v${dependencies.REALM_CORE_VERSION}-Windows-${arch}-devel.tar.gz`;
            return Promise.resolve(required);
        }
        case 'linux':
            required.CORE_SERVER_FOLDER = 'core';
            required.CORE_ARCHIVE = `realm-core-${dependencies.REALM_CORE_VERSION}.tgz`;
            required.CORE_ARCHIVE_ROOT = `realm-core-${dependencies.REALM_CORE_VERSION}`;
            return Promise.resolve(required);
        default:
            return Promise.reject(new Error(`Unsupported core platform '${options.platform}'`));
    }
}

function getSyncRequirements(dependencies, options, required = {}) {
    required.SYNC_SERVER_FOLDER = 'sync';
    let flavor = options.debug ? 'Debug' : 'Release';

    switch (options.platform) {
        case 'mac':
            required.SYNC_ARCHIVE = `realm-sync-node-cocoa-${dependencies.REALM_SYNC_VERSION}.tar.gz`;
            required.SYNC_ARCHIVE_ROOT = `realm-sync-node-cocoa-${dependencies.REALM_SYNC_VERSION}`;
            return Promise.resolve(required);
        case 'ios':
            required.SYNC_ARCHIVE = `realm-sync-cocoa-${dependencies.REALM_SYNC_VERSION}.tar.gz`;
            required.SYNC_ARCHIVE_ROOT = `core`;
            return Promise.resolve(required);
        case 'win': {
            const arch = options.arch === 'ia32' ? 'Win32' : options.arch;
            required.SYNC_ARCHIVE = `realm-sync-${flavor}-v${dependencies.REALM_SYNC_VERSION}-Windows-${arch}-devel.tar.gz`;
            return getCoreRequirements(dependencies, options, required)
                .then(() => getSyncCommitSha(dependencies.REALM_SYNC_VERSION))
                .then(sha => {
                    required.SYNC_SERVER_FOLDER += `/sha-version/${sha}`;
                    return required;
                });
        }
        case 'linux':
            required.SYNC_ARCHIVE = `realm-sync-Release-v${dependencies.REALM_SYNC_VERSION}-Linux-devel.tar.gz`;
            required.SYNC_ARCHIVE_ROOT = `realm-sync-Release-v${dependencies.REALM_SYNC_VERSION}`;
            return Promise.resolve(required);
        default:
            return Promise.reject(new Error(`Unsupported sync platform '${options.platform}'`));
    }
}

function writeLockfile(target, contents) {
    return fs.writeFile(path.resolve(target, LOCKFILE_NAME), ini.encode(contents));
}

function readLockfile(target) {
    try {
        return ini.parse(fs.readFileSync(path.resolve(target, LOCKFILE_NAME), 'utf8'));
    } catch (e) {
        return null;
    }
}

function shouldSkipAcquire(target, requirements, force) {
    if (force) {
        console.log('Skipping lockfile check as --force is enabled');
        return false;
    }

    const existingLockfile = readLockfile(target);

    if (!existingLockfile) {
        console.log('No lockfile found at the target, proceeding.');
        return false;
    }

    if (!Object.keys(requirements).every(key => existingLockfile[key] === requirements[key])) {
        console.log('Target directory has a differing lockfile, overwriting.');
        return false;
    }

    console.log('Matching lockfile already exists at target - nothing to do (use --force to override)');
    return true;
}

const optionDefinitions = [
    { name: 'platform', type: String, defaultOption: true },
    { name: 'arch', type: String },
    { name: 'sync', type: Boolean },
    { name: 'debug', type: Boolean },
    { name: 'force', type: Boolean },
];
const options = require('command-line-args')(optionDefinitions);
if (options.platform === '..\\win') {
    options.platform = 'win'; // handle gyp idiocy
}

const vendorDir = path.resolve(__dirname, '../vendor');

let realmDir = path.resolve(vendorDir, `realm-${options.platform}`);
if (options.arch) {
    realmDir += `-${options.arch}`;
}
if (options.debug) {
    realmDir += '-dbg'
}

const dependencies = ini.parse(fs.readFileSync(path.resolve(__dirname, '../dependencies.list'), 'utf8'));

(options.sync ? getSyncRequirements : getCoreRequirements)(dependencies, options)
    .then(requirements => {
        console.log('Resolved requirements:', requirements);
        if (!shouldSkipAcquire(realmDir, requirements, options.force)) {
            return acquire(requirements, realmDir)
        }
    })
    .then(() => console.log('Success'))
    .catch(error => {
        console.error(error);
        process.exit(1);
    });
<|endoftext|>


<commit_before>/**
	_moon.DateTimePickerBase_ is a base kind implementing fuctionality shared
	by _moon.DatePicker_ and _moon.TimePicker_. It is not intended to be used
	directly.
*/
enyo.kind({
	name: "moon.DateTimePickerBase",
	kind: "moon.ExpandableListItem",
	defaultKind: "enyo.Control",
	classes: "moon-expandable-picker moon-date-picker",
	events: {
		/**
			Fires when the value changes.

			_inEvent.name_ contains the name of this control.

			_inEvent.value_ contains a standard JavaScript Date object representing
			the current value.
		*/
		onChange: ""
	},
	handlers: {
		//* Handler for _onChange_ events coming from constituent controls
		onChange: "handleChangeEvent"
	},
	published: {
		//* Text to be displayed in the _currentValue_ control if no item is
		//* currently selected
		noneText: "",
		/**
			The locale (in IETF format) used for picker formatting.

			This setting only applies when the iLib library is loaded.

			* When iLib is not present, US English (en-US) formatting is applied.

			* When iLib is present and _locale_ is set to the default value (`null`),
			the picker uses iLib's current locale (which iLib tries to determine
			from the system).

			* When iLib is present and an explicit _locale_ is provided, that locale
			will be used (regardless of iLib's current locale).

			_locale_ may be changed after the picker is created, in which case the
			picker will	be reformatted to match the new setting.

		*/
		locale: null,
		/**
			The value, expressed as a standard JavaScript Date object. When a Date object
			is passed to _set("value")_, the control is updated to reflect the new
			value. _get("value")_ returns a Date object.
		*/
		value: null,
		/**
			When true, the picker uses a 12-hour clock (this value is ignored when ilib
			is loaded, since the meridiem will be set by the current locale)
		*/
		meridiemEnable: false
	},
	//*@protected
	iLibFormatType: null, // set in subkind
	defaultOrdering: null, // set in subkind
	componentOverrides: {
		headerWrapper: {components: [
			{name: "header", kind: "moon.Item", spotlight: false, classes: "moon-expandable-list-item-header moon-expandable-picker-header"},
			{name: "currentValue", kind: "moon.Item", spotlight: false, classes: "moon-expandable-picker-current-value"}
		]},
		client: {kind: "enyo.Control", classes: "enyo-tool-decorator moon-date-picker-client", onSpotlightLeft:"closePicker", onSpotlightSelect: "closePicker"}
	},
	create: function() {
		this.inherited(arguments);
		this.createComponent({kind: "enyo.Signals", onlocalechange: "handleLocaleChangeEvent"});
		this.initDefaults();
	},
	initILib: function() {
		var fmtParams = {
			type: this.iLibFormatType,
			timezone: "local",
			length: "full"
		};
		if (this.locale) {
			fmtParams.locale = this.locale;
			this.iLibLocale = null;
		} else {
			this.iLibLocale = ilib.getLocale();
		}
		this._tf = new ilib.DateFmt(fmtParams);
	},
	initDefaults: function() {
		var ordering;
		this.value = this.value || new Date();
		//Attempt to use the ilib lib (assuming that it is loaded)
		if (typeof ilib !== "undefined") {
			this.initILib();
			ordering = this._tf.getTemplate();
		} else {
			ordering = this.defaultOrdering;
		}
		this.setupPickers(ordering);
		this.noneTextChanged();
	},
	setupPickers: function(ordering) {
		// implement in subkind, calling this.inherited() at the end
		this.pickers = this.getClientControls();
	},
	formatValue: function() {
		// implement in subkind
	},
	handleChangeEvent: function(inSender, inEvent) {
		if (inEvent && inEvent.originator === this) {
			// Don't handle our own change events
			return;
		} else {
			this.updateValue(inSender, inEvent);
			return true;
		}
	},
	updateValue: function(inSender, inEvent) {
		// implement in subkind
	},
	valueChanged: function(inOld) {
		this.setChildPickers(inOld);
		this.doChange({name:this.name, value:this.value});
	},
	setChildPickers: function(inOld) {
		// implement in subkind
	},
	// If no item is selected, uses _this.noneText_ as current value.
	noneTextChanged: function() {
		if(this.value == null) {
			this.$.currentValue.setContent(this.getNoneText());
		} else {
			this.$.currentValue.setContent(this.formatValue());
		}
	},
	// When _this.open_ changes, shows/hides _this.$.currentValue_.
	openChanged: function() {
		this.inherited(arguments);
		var open = this.$.drawer.get("open"),
			pickers = this.pickers,
			i, p;
		this.$.currentValue.setShowing(!open);
		if (pickers) {
			for (i = 0; i < pickers.length; i++) {
				p = pickers[i];
				if (p.getClientControls().length > 0) {
					p = p.getClientControls()[0];
				}
				if (open) {
					//Force the pickers to update their scroll positions (they don't update while the drawer is closed)
					p.refreshScrollState();
				} else {
					// If one of the pickers is animating when the drawer closes, it won't display properly
					// when the drawer reopens, unless we stabilize here
					p.stabilize();
				}
			}
		}
	},
	toggleActive: function() {
		if (this.getOpen()) {
			this.setActive(false);
			enyo.Spotlight.spot(this.$.headerWrapper);
		} else {
			this.setActive(true);
		}
	},
	closePicker: function(inSender, inEvent) {
		//* If select/enter is pressed on any date picker item or the left key is pressed on the first item, close the drawer
		if (inEvent.type == "onSpotlightSelect" ||
			this.$.client.children[0].id == inEvent.originator.id) {
			this.updateValue(inSender, inEvent);
			this.expandContract();
			this.noneTextChanged();
			return true;
		}
	},
	localeChanged: function() {
		// Our own locale property has changed, so we need to rebuild our child pickers
		this.refresh();
	},
	handleLocaleChangeEvent: function() {
		// We've received a localechange event from the system, which means either the system
		// locale or the timzezone may have changed.
		if (ilib && ilib.getLocale() !== this.iLibLocale) {
			// We're using iLib locale, and it has changed, so we'll rebuild the child pickers entirely
			this.refresh();
		} else {
			// We don't care about the iLib locale or it hasn't changed, but timezone might have changed,
			// so we'll just update the child pickers
			this.setChildPickers();
		}
	},
	refresh: function(){
		this.destroyClientControls();
		this.pickers = null;
		if (this._tf) {
			delete this._tf;
		}
		this.initDefaults();
		this.render();
	},
	_marqueeSpotlightFocus: function(inSender, inEvent) {
		if (inSender === this) {
			this.$.header.startMarquee();
			this.$.currentValue.startMarquee();
		}
	},
	_marqueeSpotlightBlur: function(inSender, inEvent) {
		if (inSender === this) {
			this.$.header.stopMarquee();
			this.$.currentValue.stopMarquee();
		}
	}
});<commit_msg>Defect Fix - 37843 - onChange fires twice in Date/Time Picker<commit_after>/**
	_moon.DateTimePickerBase_ is a base kind implementing fuctionality shared
	by _moon.DatePicker_ and _moon.TimePicker_. It is not intended to be used
	directly.
*/
enyo.kind({
	name: "moon.DateTimePickerBase",
	kind: "moon.ExpandableListItem",
	defaultKind: "enyo.Control",
	classes: "moon-expandable-picker moon-date-picker",
	events: {
		/**
			Fires when the value changes.

			_inEvent.name_ contains the name of this control.

			_inEvent.value_ contains a standard JavaScript Date object representing
			the current value.
		*/
		onChange: ""
	},
	handlers: {
		//* Handler for _onChange_ events coming from constituent controls
		onChange: "handleChangeEvent"
	},
	published: {
		//* Text to be displayed in the _currentValue_ control if no item is
		//* currently selected
		noneText: "",
		/**
			The locale (in IETF format) used for picker formatting.

			This setting only applies when the iLib library is loaded.

			* When iLib is not present, US English (en-US) formatting is applied.

			* When iLib is present and _locale_ is set to the default value (`null`),
			the picker uses iLib's current locale (which iLib tries to determine
			from the system).

			* When iLib is present and an explicit _locale_ is provided, that locale
			will be used (regardless of iLib's current locale).

			_locale_ may be changed after the picker is created, in which case the
			picker will	be reformatted to match the new setting.

		*/
		locale: null,
		/**
			The value, expressed as a standard JavaScript Date object. When a Date object
			is passed to _set("value")_, the control is updated to reflect the new
			value. _get("value")_ returns a Date object.
		*/
		value: null,
		/**
			When true, the picker uses a 12-hour clock (this value is ignored when ilib
			is loaded, since the meridiem will be set by the current locale)
		*/
		meridiemEnable: false
	},
	//*@protected
	iLibFormatType: null, // set in subkind
	defaultOrdering: null, // set in subkind
	componentOverrides: {
		headerWrapper: {components: [
			{name: "header", kind: "moon.Item", spotlight: false, classes: "moon-expandable-list-item-header moon-expandable-picker-header"},
			{name: "currentValue", kind: "moon.Item", spotlight: false, classes: "moon-expandable-picker-current-value"}
		]},
		client: {kind: "enyo.Control", classes: "enyo-tool-decorator moon-date-picker-client", onSpotlightLeft:"closePicker", onSpotlightSelect: "closePicker"}
	},
	create: function() {
		this.inherited(arguments);
		this.createComponent({kind: "enyo.Signals", onlocalechange: "handleLocaleChangeEvent"});
		this.initDefaults();
	},
	initILib: function() {
		var fmtParams = {
			type: this.iLibFormatType,
			timezone: "local",
			length: "full"
		};
		if (this.locale) {
			fmtParams.locale = this.locale;
			this.iLibLocale = null;
		} else {
			this.iLibLocale = ilib.getLocale();
		}
		this._tf = new ilib.DateFmt(fmtParams);
	},
	initDefaults: function() {
		var ordering;
		this.value = this.value || new Date();
		//Attempt to use the ilib lib (assuming that it is loaded)
		if (typeof ilib !== "undefined") {
			this.initILib();
			ordering = this._tf.getTemplate();
		} else {
			ordering = this.defaultOrdering;
		}
		this.setupPickers(ordering);
		this.noneTextChanged();
	},
	setupPickers: function(ordering) {
		// implement in subkind, calling this.inherited() at the end
		this.pickers = this.getClientControls();
	},
	formatValue: function() {
		// implement in subkind
	},
	handleChangeEvent: function(inSender, inEvent) {
		if (inEvent && inEvent.originator === this) {
			// Don't handle our own change events
			return;
		} else {
			this.updateValue(inSender, inEvent);
			return true;
		}
	},
	updateValue: function(inSender, inEvent) {
		// implement in subkind
	},
	valueChanged: function(inOld) {
		this.setChildPickers(inOld);
	},
	setChildPickers: function(inOld) {
		// implement in subkind
	},
	// If no item is selected, uses _this.noneText_ as current value.
	noneTextChanged: function() {
		if(this.value == null) {
			this.$.currentValue.setContent(this.getNoneText());
		} else {
			this.$.currentValue.setContent(this.formatValue());
		}
	},
	// When _this.open_ changes, shows/hides _this.$.currentValue_.
	openChanged: function() {
		this.inherited(arguments);
		var open = this.$.drawer.get("open"),
			pickers = this.pickers,
			i, p;
		this.$.currentValue.setShowing(!open);
		if (pickers) {
			for (i = 0; i < pickers.length; i++) {
				p = pickers[i];
				if (p.getClientControls().length > 0) {
					p = p.getClientControls()[0];
				}
				if (open) {
					//Force the pickers to update their scroll positions (they don't update while the drawer is closed)
					p.refreshScrollState();
				} else {
					// If one of the pickers is animating when the drawer closes, it won't display properly
					// when the drawer reopens, unless we stabilize here
					p.stabilize();
				}
			}
		}
	},
	toggleActive: function() {
		if (this.getOpen()) {
			this.setActive(false);
			enyo.Spotlight.spot(this.$.headerWrapper);
		} else {
			this.setActive(true);
		}
	},
	closePicker: function(inSender, inEvent) {
		//* If select/enter is pressed on any date picker item or the left key is pressed on the first item, close the drawer
		if (inEvent.type == "onSpotlightSelect" ||
			this.$.client.children[0].id == inEvent.originator.id) {
			this.updateValue(inSender, inEvent);
			this.expandContract();
			this.noneTextChanged();
			return true;
		}
	},
	localeChanged: function() {
		// Our own locale property has changed, so we need to rebuild our child pickers
		this.refresh();
	},
	handleLocaleChangeEvent: function() {
		// We've received a localechange event from the system, which means either the system
		// locale or the timzezone may have changed.
		if (ilib && ilib.getLocale() !== this.iLibLocale) {
			// We're using iLib locale, and it has changed, so we'll rebuild the child pickers entirely
			this.refresh();
		} else {
			// We don't care about the iLib locale or it hasn't changed, but timezone might have changed,
			// so we'll just update the child pickers
			this.setChildPickers();
		}
	},
	refresh: function(){
		this.destroyClientControls();
		this.pickers = null;
		if (this._tf) {
			delete this._tf;
		}
		this.initDefaults();
		this.render();
	},
	_marqueeSpotlightFocus: function(inSender, inEvent) {
		if (inSender === this) {
			this.$.header.startMarquee();
			this.$.currentValue.startMarquee();
		}
	},
	_marqueeSpotlightBlur: function(inSender, inEvent) {
		if (inSender === this) {
			this.$.header.stopMarquee();
			this.$.currentValue.stopMarquee();
		}
	}
});<|endoftext|>


<commit_before>/**
 * Timeago is a jQuery plugin that makes it easy to support automatically
 * updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago").
 *
 * @name timeago
 * @version 1.4.1
 * @requires jQuery v1.2.3+
 * @author Ryan McGeary
 * @license MIT License - http://www.opensource.org/licenses/mit-license.php
 *
 * For usage and examples, visit:
 * http://timeago.yarp.com/
 *
 * Copyright (c) 2008-2013, Ryan McGeary (ryan -[at]- mcgeary [*dot*] org)
 */

(function (factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(['jquery'], factory);
    } else {
        // Browser globals
        factory(jQuery);
    }
}(function ($) {
    $.timeago = function(timestamp) {
        if (timestamp instanceof Date) {
            return inWords(timestamp);
        } else if (typeof timestamp === "string") {
            return inWords($.timeago.parse(timestamp));
        } else if (typeof timestamp === "number") {
            return inWords(new Date(timestamp));
        } else {
            return inWords($.timeago.datetime(timestamp));
        }
    };
    var $t = $.timeago;

    $.extend($.timeago, {
        locales: {},
        settings: {
            refreshMillis: 60000,
            allowPast: true,
            allowFuture: false,
            localeTitle: false,
            cutoff: 0,
            strings: {
                prefixAgo: null,
                prefixFromNow: null,
                suffixAgo: "ago",
                suffixFromNow: "from now",
                inPast: 'any moment now',
                seconds: "less than a minute",
                minute: "about a minute",
                minutes: "%d minutes",
                hour: "about an hour",
                hours: "about %d hours",
                day: "a day",
                days: "%d days",
                month: "about a month",
                months: "%d months",
                year: "about a year",
                years: "%d years",
                wordSeparator: " ",
                numbers: []
            }
        },

        inWords: function(distanceMillis) {
            if(!this.settings.allowPast && ! this.settings.allowFuture) {
                throw 'timeago allowPast and allowFuture settings can not both be set to false.';
            }

            var $l = this.settings.strings;
            var prefix = $l.prefixAgo;
            var suffix = $l.suffixAgo;
            if (this.settings.allowFuture) {
                if (distanceMillis < 0) {
                    prefix = $l.prefixFromNow;
                    suffix = $l.suffixFromNow;
                }
            }

            if(!this.settings.allowPast && distanceMillis >= 0) {
                return this.settings.strings.inPast;
            }

            var seconds = Math.abs(distanceMillis) / 1000;
            var minutes = seconds / 60;
            var hours = minutes / 60;
            var days = hours / 24;
            var years = days / 365;

            function substitute(stringOrFunction, number) {
                var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction;
                var value = ($l.numbers && $l.numbers[number]) || number;
                return string.replace(/%d/i, value);
            }

            var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) ||
                seconds < 90 && substitute($l.minute, 1) ||
                minutes < 45 && substitute($l.minutes, Math.round(minutes)) ||
                minutes < 90 && substitute($l.hour, 1) ||
                hours < 24 && substitute($l.hours, Math.round(hours)) ||
                hours < 42 && substitute($l.day, 1) ||
                days < 30 && substitute($l.days, Math.round(days)) ||
                days < 45 && substitute($l.month, 1) ||
                days < 365 && substitute($l.months, Math.round(days / 30)) ||
                years < 1.5 && substitute($l.year, 1) ||
                substitute($l.years, Math.round(years));

            var separator = $l.wordSeparator || "";
            if ($l.wordSeparator === undefined) { separator = " "; }
            return $.trim([prefix, words, suffix].join(separator));
        },

        parse: function(iso8601) {
            var s = $.trim(iso8601);
            s = s.replace(/\.\d+/,""); // remove milliseconds
            s = s.replace(/-/,"/").replace(/-/,"/");
            s = s.replace(/T/," ").replace(/Z/," UTC");
            s = s.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400
            s = s.replace(/([\+\-]\d\d)$/," $100"); // +09 -> +0900
            return new Date(s);
        },
        datetime: function(elem) {
            var iso8601 = $t.isTime(elem) ? $(elem).attr("datetime") : $(elem).attr("title");
            return $t.parse(iso8601);
        },
        isTime: function(elem) {
            // jQuery's `is()` doesn't play well with HTML5 in IE
            return $(elem).get(0).tagName.toLowerCase() === "time"; // $(elem).is("time");
        }
    });

    // functions that can be called via $(el).timeago('action')
    // init is default when no action is given
    // functions are called with context of a single element
    var functions = {
        init: function(){
            var refresh_el = $.proxy(refresh, this);
            refresh_el();
            var $s = $t.settings;
            if ($s.refreshMillis > 0) {
                this._timeagoInterval = setInterval(refresh_el, $s.refreshMillis);
            }
        },
        update: function(time){
            var parsedTime = $t.parse(time);
            $(this).data('timeago', { datetime: parsedTime });
            if($t.settings.localeTitle) $(this).attr("title", parsedTime.toLocaleString());
            refresh.apply(this);
        },
        updateFromDOM: function(){
            $(this).data('timeago', { datetime: $t.parse( $t.isTime(this) ? $(this).attr("datetime") : $(this).attr("title") ) });
            refresh.apply(this);
        },
        dispose: function () {
            if (this._timeagoInterval) {
                window.clearInterval(this._timeagoInterval);
                this._timeagoInterval = null;
            }
        }
    };

    $.fn.timeago = function(action, options) {
        var fn = action ? functions[action] : functions.init;
        if(!fn){
            throw new Error("Unknown function name '"+ action +"' for timeago");
        }
        // each over objects here and call the requested function
        this.each(function(){
            fn.call(this, options);
        });
        return this;
    };

    function refresh() {
        var data = prepareData(this);
        var $s = $t.settings;

        if (!isNaN(data.datetime)) {
            if ( $s.cutoff == 0 || Math.abs(distance(data.datetime)) < $s.cutoff) {
                $(this).text(inWords(data.datetime));
            }
        }
        return this;
    }

    function prepareData(element) {
        element = $(element);
        if (!element.data("timeago")) {
            element.data("timeago", { datetime: $t.datetime(element) });
            var text = $.trim(element.text());
            if ($t.settings.localeTitle) {
                element.attr("title", element.data('timeago').datetime.toLocaleString());
            } else if (text.length > 0 && !($t.isTime(element) && element.attr("title"))) {
                element.attr("title", text);
            }
        }
        return element.data("timeago");
    }

    function inWords(date) {
        return $t.inWords(distance(date));
    }

    function distance(date) {
        return (new Date().getTime() - date.getTime());
    }

    // fix for IE6 suckage
    document.createElement("abbr");
    document.createElement("time");
}));<commit_msg>Update jquery.timeago -> 1.4.3<commit_after>/**
 * Timeago is a jQuery plugin that makes it easy to support automatically
 * updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago").
 *
 * @name timeago
 * @version 1.4.3
 * @requires jQuery v1.2.3+
 * @author Ryan McGeary
 * @license MIT License - http://www.opensource.org/licenses/mit-license.php
 *
 * For usage and examples, visit:
 * http://timeago.yarp.com/
 *
 * CUSTOMIZED
 *
 * Copyright (c) 2008-2015, Ryan McGeary (ryan -[at]- mcgeary [*dot*] org)
 */

(function (factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(['jquery'], factory);
    } else if (typeof module === 'object' && typeof module.exports === 'object') {
        factory(require('jquery'));
    } else {
        // Browser globals
        factory(jQuery);
    }
}(function ($) {
    $.timeago = function(timestamp) {
        if (timestamp instanceof Date) {
            return inWords(timestamp);
        } else if (typeof timestamp === "string") {
            return inWords($.timeago.parse(timestamp));
        } else if (typeof timestamp === "number") {
            return inWords(new Date(timestamp));
        } else {
            return inWords($.timeago.datetime(timestamp));
        }
    };
    var $t = $.timeago;

    $.extend($.timeago, {
        locales: {}, // <- Customized !!
        settings: {
            refreshMillis: 60000,
            allowPast: true,
            allowFuture: false,
            localeTitle: false,
            cutoff: 0,
            strings: {
                prefixAgo: null,
                prefixFromNow: null,
                suffixAgo: "ago",
                suffixFromNow: "from now",
                inPast: 'any moment now',
                seconds: "less than a minute",
                minute: "about a minute",
                minutes: "%d minutes",
                hour: "about an hour",
                hours: "about %d hours",
                day: "a day",
                days: "%d days",
                month: "about a month",
                months: "%d months",
                year: "about a year",
                years: "%d years",
                wordSeparator: " ",
                numbers: []
            }
        },

        inWords: function(distanceMillis) {
            if(!this.settings.allowPast && ! this.settings.allowFuture) {
                throw 'timeago allowPast and allowFuture settings can not both be set to false.';
            }

            var $l = this.settings.strings;
            var prefix = $l.prefixAgo;
            var suffix = $l.suffixAgo;
            if (this.settings.allowFuture) {
                if (distanceMillis < 0) {
                    prefix = $l.prefixFromNow;
                    suffix = $l.suffixFromNow;
                }
            }

            if(!this.settings.allowPast && distanceMillis >= 0) {
                return this.settings.strings.inPast;
            }

            var seconds = Math.abs(distanceMillis) / 1000;
            var minutes = seconds / 60;
            var hours = minutes / 60;
            var days = hours / 24;
            var years = days / 365;

            function substitute(stringOrFunction, number) {
                var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction;
                var value = ($l.numbers && $l.numbers[number]) || number;
                return string.replace(/%d/i, value);
            }

            var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) ||
                seconds < 90 && substitute($l.minute, 1) ||
                minutes < 45 && substitute($l.minutes, Math.round(minutes)) ||
                minutes < 90 && substitute($l.hour, 1) ||
                hours < 24 && substitute($l.hours, Math.round(hours)) ||
                hours < 42 && substitute($l.day, 1) ||
                days < 30 && substitute($l.days, Math.round(days)) ||
                days < 45 && substitute($l.month, 1) ||
                days < 365 && substitute($l.months, Math.round(days / 30)) ||
                years < 1.5 && substitute($l.year, 1) ||
                substitute($l.years, Math.round(years));

            var separator = $l.wordSeparator || "";
            if ($l.wordSeparator === undefined) { separator = " "; }
            return $.trim([prefix, words, suffix].join(separator));
        },

        parse: function(iso8601) {
            var s = $.trim(iso8601);
            s = s.replace(/\.\d+/,""); // remove milliseconds
            s = s.replace(/-/,"/").replace(/-/,"/");
            s = s.replace(/T/," ").replace(/Z/," UTC");
            s = s.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400
            s = s.replace(/([\+\-]\d\d)$/," $100"); // +09 -> +0900
            return new Date(s);
        },
        datetime: function(elem) {
            var iso8601 = $t.isTime(elem) ? $(elem).attr("datetime") : $(elem).attr("title");
            return $t.parse(iso8601);
        },
        isTime: function(elem) {
            // jQuery's `is()` doesn't play well with HTML5 in IE
            return $(elem).get(0).tagName.toLowerCase() === "time"; // $(elem).is("time");
        }
    });

    // functions that can be called via $(el).timeago('action')
    // init is default when no action is given
    // functions are called with context of a single element
    var functions = {
        init: function(){
            var refresh_el = $.proxy(refresh, this);
            refresh_el();
            var $s = $t.settings;
            if ($s.refreshMillis > 0) {
                this._timeagoInterval = setInterval(refresh_el, $s.refreshMillis);
            }
        },
        update: function(time){
            var parsedTime = $t.parse(time);
            $(this).data('timeago', { datetime: parsedTime });
            if($t.settings.localeTitle) $(this).attr("title", parsedTime.toLocaleString());
            refresh.apply(this);
        },
        updateFromDOM: function(){
            $(this).data('timeago', { datetime: $t.parse( $t.isTime(this) ? $(this).attr("datetime") : $(this).attr("title") ) });
            refresh.apply(this);
        },
        dispose: function () {
            if (this._timeagoInterval) {
                window.clearInterval(this._timeagoInterval);
                this._timeagoInterval = null;
            }
        }
    };

    $.fn.timeago = function(action, options) {
        var fn = action ? functions[action] : functions.init;
        if(!fn){
            throw new Error("Unknown function name '"+ action +"' for timeago");
        }
        // each over objects here and call the requested function
        this.each(function(){
            fn.call(this, options);
        });
        return this;
    };

    function refresh() {
        //check if it's still visible
        if(!$.contains(document.documentElement,this)){
            //stop if it has been removed
            $(this).timeago("dispose");
            return this;
        }

        var data = prepareData(this);
        var $s = $t.settings;

        if (!isNaN(data.datetime)) {
            if ( $s.cutoff == 0 || Math.abs(distance(data.datetime)) < $s.cutoff) {
                $(this).text(inWords(data.datetime));
            }
        }
        return this;
    }

    function prepareData(element) {
        element = $(element);
        if (!element.data("timeago")) {
            element.data("timeago", { datetime: $t.datetime(element) });
            var text = $.trim(element.text());
            if ($t.settings.localeTitle) {
                element.attr("title", element.data('timeago').datetime.toLocaleString());
            } else if (text.length > 0 && !($t.isTime(element) && element.attr("title"))) {
                element.attr("title", text);
            }
        }
        return element.data("timeago");
    }

    function inWords(date) {
        return $t.inWords(distance(date));
    }

    function distance(date) {
        return (new Date().getTime() - date.getTime());
    }

    // fix for IE6 suckage
    document.createElement("abbr");
    document.createElement("time");
}));<|endoftext|>


<commit_before>var prolific = require('prolific')

function Logger (context) {
    this.context = context
    this._path = ('.' + context).split('.')
}

; [ 'error', 'warn', 'info', 'debug', 'trace' ].forEach(function (level) {
    Logger.prototype[level] = function (name, properties) {
        prolific.json(this._path, level, this.context, name, properties)
    }
})

Logger.createLogger = function (context) { return new Logger(context) }

module.exports = Logger
<commit_msg>Rename `context` to `qualifier`.<commit_after>var prolific = require('prolific')

function Logger (qualifier) {
    this.qualifier = qualifier
    this._path = ('.' + qualifier).split('.')
}

; [ 'error', 'warn', 'info', 'debug', 'trace' ].forEach(function (level) {
    Logger.prototype[level] = function (name, properties) {
        prolific.json(this._path, level, this.qualifier, name, properties)
    }
})

Logger.createLogger = function (context) { return new Logger(context) }

module.exports = Logger
<|endoftext|>


<commit_before>// Load in our dependencies
var assert = require('assert');
var async = require('async');
var browser = require('wd').remote();

// Dump cookies via node CLI
/*
node

// Inside of CLI
var browser = require('wd').remote();
browser.init({browserName: 'chrome'}, console.log);
// Wait for browser window to open
browser.get('https://play.google.com/music/listen', console.log);
// Wait for redirect to accounts.google.com
// Manually log in to page
// When you are logged in to Google Music, dump the output of the following into `cookies.json`
browser.allCookies(function (err, cookies) { console.log(JSON.stringify(cookies, null, 4))});
*/

var cookies = require('./cookies');

// Open Google Music
browser.init({browserName: 'chrome'}, function () {
  browser.get('https://play.google.com/music/listen', function () {
    async.forEach(cookies, function setCookies (cookie, cb) {
      browser.setCookie(cookie, cb);
    }, function handleSetCookies (err) {
      // If there was an error, throw it
      if (err) {
        throw err;
      }

      // Otherwise, continue
      browser.title(function handleTitle (err, title) {
        console.log(title);
      });
    });
      // // title.should.include('WD');
      // console.log(title);
      // browser.elementById('i am a link', function handleLink (err, el) {
      //   browser.clickElement(el, function() {
      //     /* jshint evil: true */
      //     browser.eval("window.location.href", function handleEval (err, href) {
            // console.log(href);
            // href.should.include('guinea-pig2');
            // browser.quit();
    //       });
    //     });
    //   });
    // });
  });
});
<commit_msg>Ran into issue with setting cookies<commit_after>// Load in our dependencies
var assert = require('assert');
var async = require('async');
var browser = require('wd').remote();

// Dump cookies via node CLI
/*
node

// Inside of CLI
var browser = require('wd').remote();
browser.init({browserName: 'chrome'}, console.log);
// Wait for browser window to open
browser.get('https://play.google.com/music/listen', console.log);
// Wait for redirect to accounts.google.com
// Manually log in to page
// When you are logged in to Google Music, dump the output of the following into `cookies.json`
browser.allCookies(function (err, cookies) { console.log(JSON.stringify(cookies, null, 4))});
*/

var cookies = require('./cookies');

// Open Google Music
browser.init({browserName: 'chrome'}, function () {
  browser.get('https://play.google.com/music/listen', function () {
    async.forEach(cookies, function setCookies (cookie, cb) {
      // If the cookie is not for .google.com, skip it
      if (cookie.domain !== '.google.com') {
        process.nextTick(cb);
      // Otherwise, set it
      } else {
        browser.setCookie(cookie, cb);
      }
    }, function handleSetCookies (err) {
      // If there was an error, throw it
      if (err) {
        throw err;
      }

      // Otherwise, navigate back to Google Music
      browser.get('https://play.google.com/music/listen', function () {
        browser.title(function handleTitle (err, title) {
          console.log(title);
        });
      });
    });
      // // title.should.include('WD');
      // console.log(title);
      // browser.elementById('i am a link', function handleLink (err, el) {
      //   browser.clickElement(el, function() {
      //     /* jshint evil: true */
      //     browser.eval("window.location.href", function handleEval (err, href) {
            // console.log(href);
            // href.should.include('guinea-pig2');
            // browser.quit();
    //       });
    //     });
    //   });
    // });
  });
});
<|endoftext|>


<commit_before>(function() {

    //Constants
    var ONE_DAY_MS = 86400000;
    var ONE_WEEK_MS = 604800000;
    var PAINT_DELAY_MS = 1000;

    // CHECK D3
    if(typeof d3 === 'undefined') {
        console.error("Heatmap could not be loaded because d3 did not exist.");
        return;
    }

    // Configuration checker
    var normalizeConfig = function normalizeConfig(configuration) {

        if (configuration == null) {
            configuration = {};
        }

        if(!(configuration['colors'] instanceof Array)) {
            configuration['colors'] = ['#F6FAAA','#FEE08B','#FDAE61','#F46D43','#D53E4F','#9E0142'];
        }

        return configuration;
    };

    // BASIC METHODS - - - - - - - - - - - - - - - - - - - - - -

    var Heatmap = function Heatmap(element, metrics, contextId, configuration) {

        if(!framework.isReady()) {
            console.error("Heatmap object could not be created because framework is not loaded.");
            return;
        }

        if(metrics.length > 1) {
            metrics = metrics.splice(1, metrics.length-1);
            console.warn("This widget only allows one metric. The other metrics will be ignored.");
        }

        this.element = $(element); //Store as jquery object
        this.svg = null;
        this.data = null;
        this.aspect = null;
        this.resizeEventHandler = null;
        this.painted = false;
        this.metricId = metrics[0]['id'];
        this.maxValue = -1;
        this.minValue = Infinity;

        // Extending widget
        framework.widgets.CommonWidget.call(this, false, this.element.get(0));

        // Configuration
        this.configuration = normalizeConfig(configuration);

        this.observeCallback = function(data){
            this.updateData(data);
        }.bind(this);

        framework.metrics.observe(metrics, this.observeCallback , contextId);

    };

    Heatmap.prototype = new framework.widgets.CommonWidget(true);

    Heatmap.prototype.updateData = function(data) {
        this.delete();
        this.data = data[this.metricId];
        paint.call(this);
    };

    Heatmap.prototype.delete = function() {

        if(!this.painted)
            return;

        //Stop listening to window resize events
        $(window).off("resize", this.resizeEventHandler);
        this.resizeEventHandler = null;

        //Stop observing for data changes
        framework.metrics.stopObserve(this.observeCallback);

        //Clear DOM
        this.svg.empty();
        this.element.empty();

        this.painted = false;

    };

    // PRIVATE METHODS - - - - - - - - - - - - - - - - - - - - - -

    var updateSize = function updateSize() {

        var parentWidth = this.svg.parent().get(0).getBoundingClientRect().width;
        var parentHeight = this.svg.parent().get(0).getBoundingClientRect().height;
        var parentAspect = parentWidth / parentHeight;
        if(parentAspect <= this.aspect){
            this.svg.attr('width', parentWidth);
            this.svg.attr('height', parentWidth / this.aspect);
        } else {
            this.svg.attr('width', parentHeight * this.aspect);
            this.svg.attr('height', parentHeight);
        }
    };

    var renderColor = function renderColor(rect, dateExtent){

        rect
            .filter(function(value){
                return value >= 0;
            })
            .transition()
            .delay(function(d, index){
                var max = dateExtent[1].getTime();
                var min = dateExtent[0].getTime();
                var current = dateExtent[0].getTime() + index * this.data['step'];
                return PAINT_DELAY_MS * (current - min)/(max - min);
            }.bind(this))
            .duration(500)
            .attrTween('fill',function(value,i,a){
                //choose color dynamically
                var colorIndex = d3.scale.quantize()
                    .range(d3.range(0, this.configuration['colors'].length, 1))
                    .domain([this.minValue, this.maxValue]);
                return d3.interpolate(a, this.configuration['colors'][colorIndex(value)]);
            }.bind(this));
    };

    var paint = function paint() {

        if(this.data == null) {
            return; // Nothing to paint
        }

        if(this.painted) {
            this.updateSize();
            return;
        }

        // Add an svg element to draw in it
        this.element.append('<svg role="heatmap" class="heatmap blurable" preserveAspectRatio="xMidYMid"></svg>');
        this.svg = this.element.children("svg");
        this.element.append(this.svg);

        // Metric values
        var dataValues = this.data['values'];

        //UI configuration
        var itemSize = 18,
            cellSize = itemSize-1,
            width = this.element.width(),
            height = this.element.height(),
            margin = {top:20,right:20,bottom:20,left:40};

        //formats
        var dateFormat = d3.time.format('%m/%d/%Y'),
            monthNameFormat = d3.time.format('%b'),
            weekDayFormat = d3.time.format("%w");

        //axises and scales
        var axisWidth = 0 ,
            axisHeight = itemSize*7,
            xAxisScale = d3.time.scale(),
            yAxisScale = d3.scale.linear(),
            xAxis = d3.svg.axis()
                .orient('top')
                .ticks(d3.time.months,1)
                .tickFormat(monthNameFormat),
            weekDayNames = ["Sun", "Mon", "Tues", "Wed", "Thurs", "Fri", "Sat"];
        yAxis = d3.svg.axis()
            .orient('left')
            .ticks(7)
            .tickFormat(function(d, i){
                return weekDayNames[d];
            });

        var d3svg = d3.select(this.svg.get(0));
        var heatmap = d3svg
            .attr('width',width)
            .attr('height',height)
            .style('max-height', height)
            .append('g')
            .attr('width',width-margin.left-margin.right)
            .attr('height',height-margin.top-margin.bottom)
            .attr('class','heatmap-content')
            .attr('transform','translate('+margin.left+','+margin.top+')');

        var rect = null;
        var dailyValues = [];

        //Create a date extent object with the from and to dates
        var dateExtent = [new Date(this.data['interval']['from']), new Date(this.data['interval']['to'])];

        //Clean the from date to start from midnight
        var firstDay = new Date(dateExtent[0]);
        firstDay.setHours(0);
        firstDay.setMinutes(0);
        firstDay.setMilliseconds(0);

        dataValues.forEach(function(value,index){

            //Given the data index and the from date, calculate the current date
            var curDate = dateExtent[0].getTime() + index * this.data['step'];

            //How many days has been since the from date
            var day = Math.floor((curDate - firstDay) / ONE_DAY_MS);

            //Increment the value for that day
            dailyValues[day] = (dailyValues[day] != null ? dailyValues[day] + value : value);

        }.bind(this));

        this.maxValue = -1;
        this.minValue = Infinity;

        //Get the min and max values (to create later the color scale)
        dailyValues.forEach(function(value){
            this.minValue = d3.min([this.minValue, value]);
            this.maxValue = d3.max([this.maxValue, value]);
        }.bind(this));

        //Number of weeks to be displayed in the chart
        var numWeeks = Math.ceil((dateExtent[1] - dateExtent[0] + weekDayFormat(dateExtent[0]) * ONE_DAY_MS) / ONE_WEEK_MS);

        axisWidth = itemSize * numWeeks; //53 weeks in a year

        //render axises
        xAxis.scale(xAxisScale.range([0,axisWidth]).domain([dateExtent[0],dateExtent[1]]));
        yAxis.scale(yAxisScale.range([0,axisHeight]).domain([0,6]));

        d3svg.append('g')
            .attr('transform','translate('+margin.left+','+margin.top+')')
            .attr('class','x axis')
            .call(xAxis);
        d3svg.append('g')
            .attr('transform','translate('+margin.left+','+margin.top+')')
            .attr('class','y axis')
            .call(yAxis);

        //render heatmap rects
        rect = heatmap.selectAll('rect')
            .data(dailyValues)
            .enter().append('rect')
            .attr('width',cellSize)
            .attr('height',cellSize)
            .attr('x',function(d,index){
                var curDate = dateExtent[0].getTime() + index * ONE_DAY_MS;
                return itemSize * Math.floor((curDate - firstDay + weekDayFormat(firstDay) * ONE_DAY_MS) / ONE_WEEK_MS);
            })
            .attr('y',function(d,index){
                var curDate = dateExtent[0].getTime() + index * ONE_DAY_MS;
                return weekDayFormat(new Date(curDate))*itemSize;
            })
            .attr('fill','#ffffff');

        rect.filter(function(value){ return value>0;})
            .append('title')
            .text(function(value, index){
                var curDate = dateExtent[0].getTime() + index * ONE_DAY_MS;
                return dateFormat(new Date(curDate))+': '+value;
            });

        renderColor.call(this, rect, dateExtent);

        var chartWidth = numWeeks * itemSize + margin.left + margin.right;
        var chartHeight = 7 * itemSize + margin.top + margin.bottom;
        d3svg.attr('viewBox', '0 0 '+chartWidth+' '+chartHeight);
        this.aspect = chartWidth / chartHeight;

        this.resizeEventHandler = updateSize.bind(this);
        $(window).resize(this.resizeEventHandler);

        updateSize.call(this);

    };

    window.framework.widgets.Heatmap = Heatmap;

})();<commit_msg>[Widget] [Heatmap] Added support for the new events in observe callback.<commit_after>(function() {

    //Constants
    var ONE_DAY_MS = 86400000;
    var ONE_WEEK_MS = 604800000;
    var PAINT_DELAY_MS = 1000;

    // CHECK D3
    if(typeof d3 === 'undefined') {
        console.error("Heatmap could not be loaded because d3 did not exist.");
        return;
    }

    // Configuration checker
    var normalizeConfig = function normalizeConfig(configuration) {

        if (configuration == null) {
            configuration = {};
        }

        if(!(configuration['colors'] instanceof Array)) {
            configuration['colors'] = ['#F6FAAA','#FEE08B','#FDAE61','#F46D43','#D53E4F','#9E0142'];
        }

        return configuration;
    };

    // BASIC METHODS - - - - - - - - - - - - - - - - - - - - - -

    var Heatmap = function Heatmap(element, metrics, contextId, configuration) {

        if(!framework.isReady()) {
            console.error("Heatmap object could not be created because framework is not loaded.");
            return;
        }

        if(metrics.length > 1) {
            metrics = metrics.splice(1, metrics.length-1);
            console.warn("This widget only allows one metric. The other metrics will be ignored.");
        }

        this.element = $(element); //Store as jquery object
        this.svg = null;
        this.data = null;
        this.aspect = null;
        this.resizeEventHandler = null;
        this.painted = false;
        this.metricId = metrics[0]['id'];
        this.maxValue = -1;
        this.minValue = Infinity;

        // Extending widget
        framework.widgets.CommonWidget.call(this, false, this.element.get(0));

        // Configuration
        this.configuration = normalizeConfig(configuration);

        this.observeCallback = function(event){

            if(event.event === 'loading') {
                this.startLoading();
            } else if(event.event === 'data') {
                this.updateData(event.data);
                this.endLoading();
            }

        }.bind(this);

        framework.metrics.observe(metrics, this.observeCallback , contextId);

    };

    Heatmap.prototype = new framework.widgets.CommonWidget(true);

    Heatmap.prototype.updateData = function(data) {
        this.delete();
        this.data = data[this.metricId];
        paint.call(this);
    };

    Heatmap.prototype.delete = function() {

        if(!this.painted)
            return;

        //Stop listening to window resize events
        $(window).off("resize", this.resizeEventHandler);
        this.resizeEventHandler = null;

        //Stop observing for data changes
        framework.metrics.stopObserve(this.observeCallback);

        //Clear DOM
        this.svg.empty();
        this.element.empty();

        this.painted = false;

    };

    // PRIVATE METHODS - - - - - - - - - - - - - - - - - - - - - -

    var updateSize = function updateSize() {

        var parentWidth = this.svg.parent().get(0).getBoundingClientRect().width;
        var parentHeight = this.svg.parent().get(0).getBoundingClientRect().height;
        var parentAspect = parentWidth / parentHeight;
        if(parentAspect <= this.aspect){
            this.svg.attr('width', parentWidth);
            this.svg.attr('height', parentWidth / this.aspect);
        } else {
            this.svg.attr('width', parentHeight * this.aspect);
            this.svg.attr('height', parentHeight);
        }
    };

    var renderColor = function renderColor(rect, dateExtent){

        rect
            .filter(function(value){
                return value >= 0;
            })
            .transition()
            .delay(function(d, index){
                var max = dateExtent[1].getTime();
                var min = dateExtent[0].getTime();
                var current = dateExtent[0].getTime() + index * this.data['step'];
                return PAINT_DELAY_MS * (current - min)/(max - min);
            }.bind(this))
            .duration(500)
            .attrTween('fill',function(value,i,a){
                //choose color dynamically
                var colorIndex = d3.scale.quantize()
                    .range(d3.range(0, this.configuration['colors'].length, 1))
                    .domain([this.minValue, this.maxValue]);
                return d3.interpolate(a, this.configuration['colors'][colorIndex(value)]);
            }.bind(this));
    };

    var paint = function paint() {

        if(this.data == null) {
            return; // Nothing to paint
        }

        if(this.painted) {
            this.updateSize();
            return;
        }

        // Add an svg element to draw in it
        this.element.append('<svg role="heatmap" class="heatmap blurable" preserveAspectRatio="xMidYMid"></svg>');
        this.svg = this.element.children("svg");
        this.element.append(this.svg);

        // Metric values
        var dataValues = this.data['values'];

        //UI configuration
        var itemSize = 18,
            cellSize = itemSize-1,
            width = this.element.width(),
            height = this.element.height(),
            margin = {top:20,right:20,bottom:20,left:40};

        //formats
        var dateFormat = d3.time.format('%m/%d/%Y'),
            monthNameFormat = d3.time.format('%b'),
            weekDayFormat = d3.time.format("%w");

        //axises and scales
        var axisWidth = 0 ,
            axisHeight = itemSize*7,
            xAxisScale = d3.time.scale(),
            yAxisScale = d3.scale.linear(),
            xAxis = d3.svg.axis()
                .orient('top')
                .ticks(d3.time.months,1)
                .tickFormat(monthNameFormat),
            weekDayNames = ["Sun", "Mon", "Tues", "Wed", "Thurs", "Fri", "Sat"];
        yAxis = d3.svg.axis()
            .orient('left')
            .ticks(7)
            .tickFormat(function(d, i){
                return weekDayNames[d];
            });

        var d3svg = d3.select(this.svg.get(0));
        var heatmap = d3svg
            .attr('width',width)
            .attr('height',height)
            .style('max-height', height)
            .append('g')
            .attr('width',width-margin.left-margin.right)
            .attr('height',height-margin.top-margin.bottom)
            .attr('class','heatmap-content')
            .attr('transform','translate('+margin.left+','+margin.top+')');

        var rect = null;
        var dailyValues = [];

        //Create a date extent object with the from and to dates
        var dateExtent = [new Date(this.data['interval']['from']), new Date(this.data['interval']['to'])];

        //Clean the from date to start from midnight
        var firstDay = new Date(dateExtent[0]);
        firstDay.setHours(0);
        firstDay.setMinutes(0);
        firstDay.setMilliseconds(0);

        dataValues.forEach(function(value,index){

            //Given the data index and the from date, calculate the current date
            var curDate = dateExtent[0].getTime() + index * this.data['step'];

            //How many days has been since the from date
            var day = Math.floor((curDate - firstDay) / ONE_DAY_MS);

            //Increment the value for that day
            dailyValues[day] = (dailyValues[day] != null ? dailyValues[day] + value : value);

        }.bind(this));

        this.maxValue = -1;
        this.minValue = Infinity;

        //Get the min and max values (to create later the color scale)
        dailyValues.forEach(function(value){
            this.minValue = d3.min([this.minValue, value]);
            this.maxValue = d3.max([this.maxValue, value]);
        }.bind(this));

        //Number of weeks to be displayed in the chart
        var numWeeks = Math.ceil((dateExtent[1] - dateExtent[0] + weekDayFormat(dateExtent[0]) * ONE_DAY_MS) / ONE_WEEK_MS);

        axisWidth = itemSize * numWeeks; //53 weeks in a year

        //render axises
        xAxis.scale(xAxisScale.range([0,axisWidth]).domain([dateExtent[0],dateExtent[1]]));
        yAxis.scale(yAxisScale.range([0,axisHeight]).domain([0,6]));

        d3svg.append('g')
            .attr('transform','translate('+margin.left+','+margin.top+')')
            .attr('class','x axis')
            .call(xAxis);
        d3svg.append('g')
            .attr('transform','translate('+margin.left+','+margin.top+')')
            .attr('class','y axis')
            .call(yAxis);

        //render heatmap rects
        rect = heatmap.selectAll('rect')
            .data(dailyValues)
            .enter().append('rect')
            .attr('width',cellSize)
            .attr('height',cellSize)
            .attr('x',function(d,index){
                var curDate = dateExtent[0].getTime() + index * ONE_DAY_MS;
                return itemSize * Math.floor((curDate - firstDay + weekDayFormat(firstDay) * ONE_DAY_MS) / ONE_WEEK_MS);
            })
            .attr('y',function(d,index){
                var curDate = dateExtent[0].getTime() + index * ONE_DAY_MS;
                return weekDayFormat(new Date(curDate))*itemSize;
            })
            .attr('fill','#ffffff');

        rect.filter(function(value){ return value>0;})
            .append('title')
            .text(function(value, index){
                var curDate = dateExtent[0].getTime() + index * ONE_DAY_MS;
                return dateFormat(new Date(curDate))+': '+value;
            });

        renderColor.call(this, rect, dateExtent);

        var chartWidth = numWeeks * itemSize + margin.left + margin.right;
        var chartHeight = 7 * itemSize + margin.top + margin.bottom;
        d3svg.attr('viewBox', '0 0 '+chartWidth+' '+chartHeight);
        this.aspect = chartWidth / chartHeight;

        this.resizeEventHandler = updateSize.bind(this);
        $(window).resize(this.resizeEventHandler);

        updateSize.call(this);

    };

    window.framework.widgets.Heatmap = Heatmap;

})();<|endoftext|>


<commit_before>(function (controllers, undefined) {

    /**
     * @ngdoc controller
     * @name Merchello.Dashboards.Order.Dialogs.FulfillShipmentController
     * @function
     *
     * @description
     * The controller for the fulfillment of shipments on the Order View page
     */
	controllers.FulfillShipmentController = function ($scope, merchelloOrderService, merchelloShipmentService, notificationsService, merchelloSettingsService) {

        $scope.getShipMethodForOrder = function (order) {
            var promise = merchelloShipmentService.getShipMethod(order);
            promise.then(function (method) {
                $scope.shipMethod = new merchello.Models.ShippingMethod(method);
            }, function (reason) {
                notificationsService.error("Shipment Methods Load Failed", reason.message);
            });
        };

	    /**
         * @ngdoc method
         * @name getUnFulfilledItems
         * @function
         *
         * @description
         * Get all the currently unfulfilled items in the order.
         */
        $scope.getUnFulfilledItems = function (orderKey) {
            var promise = merchelloOrderService.getUnFulfilledItems(orderKey);
            promise.then(function (items) {
                $scope.dialogData.items = _.map(items, function (item) {
                    return new merchello.Models.OrderLineItem(item);
                });
                _.each($scope.dialogData.items, function(item) {
                    if (!item.backOrder) {
                        item.selected = true;
                    } else {
                        item.selected = false;
                    }
                });
            }, function (reason) {
                notificationsService.error("Line Items Load Failed", reason.message);
            });
        };

	    /**
         * @ngdoc method
         * @name loadSettings
         * @function
         *
         * @description
         * Load settings like currency symbols.
         */
        $scope.loadSettings = function () {
        	var currencySymbolPromise = merchelloSettingsService.getCurrencySymbol();
        	currencySymbolPromise.then(function (currencySymbol) {
        		$scope.currencySymbol = currencySymbol;
        	}, function (reason) {
        		alert('Failed: ' + reason.message);
        	});
        };

        /**
         * @ngdoc method
         * @name init
         * @function
         *
         * @description
         * Method called on intial page load.  Loads in data from server and sets up scope.
         */
        $scope.init = function () {
            $scope.setVariables();
        	$scope.loadSettings();
            $scope.getUnFulfilledItems($scope.dialogData.key);
            $scope.getShipMethodForOrder($scope.dialogData);
        };

	    /**
         * @ngdoc method
         * @name save
         * @function
         *
         * @description
         */
	    $scope.save = function() {
	        console.info($scope.dialogData.items);
            // $scope.submit(dialogData);
	    };

	    /**
         * @ngdoc method
         * @name setVariables
         * @function
         *
         * @description
         * Set variables to their default/starting state on the $scope.
         */
	    $scope.setVariables = function() {
	        $scope.dialogData.trackingNumber = "";
	        $scope.shipMethod = {};
	    };

        $scope.init();
    };

	angular.module("umbraco").controller("Merchello.Dashboards.Order.Dialogs.FulfillShipmentController", ['$scope', 'merchelloOrderService', 'merchelloShipmentService', 'notificationsService', 'merchelloSettingsService', merchello.Controllers.FulfillShipmentController]);

}(window.merchello.Controllers = window.merchello.Controllers || {}));
<commit_msg>Updated fulfill.shipment.controller.js to remove the items that aren't selected for fulfillment before submitting, to match model required by API NewShipMethod endpoint.<commit_after>(function (controllers, undefined) {

    /**
     * @ngdoc controller
     * @name Merchello.Dashboards.Order.Dialogs.FulfillShipmentController
     * @function
     *
     * @description
     * The controller for the fulfillment of shipments on the Order View page
     */
	controllers.FulfillShipmentController = function ($scope, merchelloOrderService, merchelloShipmentService, notificationsService, merchelloSettingsService) {

        $scope.getShipMethodForOrder = function (order) {
            var promise = merchelloShipmentService.getShipMethod(order);
            promise.then(function (method) {
                $scope.shipMethod = new merchello.Models.ShippingMethod(method);
            }, function (reason) {
                notificationsService.error("Shipment Methods Load Failed", reason.message);
            });
        };

	    /**
         * @ngdoc method
         * @name getUnFulfilledItems
         * @function
         *
         * @description
         * Get all the currently unfulfilled items in the order.
         */
        $scope.getUnFulfilledItems = function (orderKey) {
            var promise = merchelloOrderService.getUnFulfilledItems(orderKey);
            promise.then(function (items) {
                $scope.dialogData.items = _.map(items, function (item) {
                    return new merchello.Models.OrderLineItem(item);
                });
                _.each($scope.dialogData.items, function(item) {
                    if (!item.backOrder) {
                        item.selected = true;
                    } else {
                        item.selected = false;
                    }
                });
            }, function (reason) {
                notificationsService.error("Line Items Load Failed", reason.message);
            });
        };

	    /**
         * @ngdoc method
         * @name loadSettings
         * @function
         *
         * @description
         * Load settings like currency symbols.
         */
        $scope.loadSettings = function () {
        	var currencySymbolPromise = merchelloSettingsService.getCurrencySymbol();
        	currencySymbolPromise.then(function (currencySymbol) {
        		$scope.currencySymbol = currencySymbol;
        	}, function (reason) {
        		alert('Failed: ' + reason.message);
        	});
        };

        /**
         * @ngdoc method
         * @name init
         * @function
         *
         * @description
         * Method called on intial page load.  Loads in data from server and sets up scope.
         */
        $scope.init = function () {
            $scope.setVariables();
        	$scope.loadSettings();
            $scope.getUnFulfilledItems($scope.dialogData.key);
            $scope.getShipMethodForOrder($scope.dialogData);
        };

	    /**
         * @ngdoc method
         * @name save
         * @function
         *
         * @description
         */
        $scope.save = function () {
            $scope.dialogData.items = _.filter($scope.dialogData.items, function (item) {
                return item.selected == true;
            });
            $scope.submit($scope.dialogData);
        };

	    /**
         * @ngdoc method
         * @name setVariables
         * @function
         *
         * @description
         * Set variables to their default/starting state on the $scope.
         */
	    $scope.setVariables = function() {
	        $scope.dialogData.trackingNumber = "";
	        $scope.shipMethod = {};
	    };

        $scope.init();
    };

	angular.module("umbraco").controller("Merchello.Dashboards.Order.Dialogs.FulfillShipmentController", ['$scope', 'merchelloOrderService', 'merchelloShipmentService', 'notificationsService', 'merchelloSettingsService', merchello.Controllers.FulfillShipmentController]);

}(window.merchello.Controllers = window.merchello.Controllers || {}));
<|endoftext|>


<commit_before><commit_msg>Abbreviates months on user dashboard chart<commit_after><|endoftext|>