<commit_before>var webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HTMLWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');

module.exports = {
	entry: {
		main: './src/client/main.js',
		admin: './src/client/admin.js',
		vendor: [
			'@blueprintjs/core',
			'axios',
			'babel-polyfill',
			'core-js',
			'history',
			'lodash.merge',
			'localforage',
			'marked',
			'react',
			'react-animate-on-scroll',
			'react-apollo',
			'redux-devtools-extension',
			'react-dom',
			'react-redux',
			'react-responsive',
			'react-router-dom',
			'react-transition-group',
			'redux-storage',
			'redux',
			'redux-logger',
			'redux-promise-middleware',
			'redux-storage-engine-localforage',
			'redux-thunk'
		]
	},
	module: {
		rules: [
			{
				test: /\.js?$/,
				exclude: /(node_modules)/,
				use: [
					{
						loader: 'babel-loader',
						options: {
							presets: ['react', 'es2015', 'stage-0'],
							plugins: ['react-html-attrs', 'transform-class-properties', 'transform-decorators-legacy']
						}
					}
				]
			},
			{
				test: /\.scss$/,
				use: ExtractTextPlugin.extract({
					fallback: 'style-loader',
					use: [
						{ loader: 'css-loader?sourceMap', options: { minimize: true } },
						{ loader: 'sass-loader?sourceMap' }
					]
				})
			},
			{
				test: /\.(ico)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
				loader: 'file-loader', options: {name: '[name].[ext]'}
			},
			{
				test: /\.(woff|woff2|eot|ttf|otf)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
				loader: 'file-loader', options: {name: 'fonts/[name].[ext]'}
			},
			{
				test: /\.(jpg|gif|png|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
				loader: 'file-loader', options: {name: 'images/[name].[ext]'}
			}
		]
	},
	output: {
		path: __dirname + '/../public',
		filename: 'js/[name]-[chunkhash].min.js',
		publicPath: '/'
	},
	plugins: [
		new CleanWebpackPlugin([
			'public/css/*.css',
			'public/js/*.js',
			'public/js/*.map'
		],
		{ root: __dirname + '/..' }),

		new webpack.DefinePlugin({
			'process.env':{
				'NODE_ENV': JSON.stringify(process.env.NODE_ENV)
			}
		}),

		new webpack.optimize.CommonsChunkPlugin({
			name: 'vendor',
			minChunks: Infinity
		}),

		new ExtractTextPlugin('css/[name]-[chunkhash].css'),

		new HTMLWebpackPlugin({
			filename: 'index.html',
			chunks: ['vendor', 'main'],
			template: 'src/client/assets/index.html'
		}),

		new HTMLWebpackPlugin({
			filename: 'admin.html',
			chunks: ['vendor', 'admin'],
			template: 'src/client/assets/admin.html'
		})
	],
	devtool: 'source-map'
};
<commit_msg>[FIX] Remove css map files on rebuild<commit_after>var webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HTMLWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');

module.exports = {
	entry: {
		main: './src/client/main.js',
		admin: './src/client/admin.js',
		vendor: [
			'@blueprintjs/core',
			'axios',
			'babel-polyfill',
			'core-js',
			'history',
			'lodash.merge',
			'localforage',
			'marked',
			'react',
			'react-animate-on-scroll',
			'react-apollo',
			'redux-devtools-extension',
			'react-dom',
			'react-redux',
			'react-responsive',
			'react-router-dom',
			'react-transition-group',
			'redux-storage',
			'redux',
			'redux-logger',
			'redux-promise-middleware',
			'redux-storage-engine-localforage',
			'redux-thunk'
		]
	},
	module: {
		rules: [
			{
				test: /\.js?$/,
				exclude: /(node_modules)/,
				use: [
					{
						loader: 'babel-loader',
						options: {
							presets: ['react', 'es2015', 'stage-0'],
							plugins: ['react-html-attrs', 'transform-class-properties', 'transform-decorators-legacy']
						}
					}
				]
			},
			{
				test: /\.scss$/,
				use: ExtractTextPlugin.extract({
					fallback: 'style-loader',
					use: [
						{ loader: 'css-loader?sourceMap', options: { minimize: true } },
						{ loader: 'sass-loader?sourceMap' }
					]
				})
			},
			{
				test: /\.(ico)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
				loader: 'file-loader', options: {name: '[name].[ext]'}
			},
			{
				test: /\.(woff|woff2|eot|ttf|otf)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
				loader: 'file-loader', options: {name: 'fonts/[name].[ext]'}
			},
			{
				test: /\.(jpg|gif|png|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
				loader: 'file-loader', options: {name: 'images/[name].[ext]'}
			}
		]
	},
	output: {
		path: __dirname + '/../public',
		filename: 'js/[name]-[chunkhash].min.js',
		publicPath: '/'
	},
	plugins: [
		new CleanWebpackPlugin([
			'public/css/*.css',
			'public/css/*.map',
			'public/js/*.js',
			'public/js/*.map'
		],
		{ root: __dirname + '/..' }),

		new webpack.DefinePlugin({
			'process.env':{
				'NODE_ENV': JSON.stringify(process.env.NODE_ENV)
			}
		}),

		new webpack.optimize.CommonsChunkPlugin({
			name: 'vendor',
			minChunks: Infinity
		}),

		new ExtractTextPlugin('css/[name]-[chunkhash].css'),

		new HTMLWebpackPlugin({
			filename: 'index.html',
			chunks: ['vendor', 'main'],
			template: 'src/client/assets/index.html'
		}),

		new HTMLWebpackPlugin({
			filename: 'admin.html',
			chunks: ['vendor', 'admin'],
			template: 'src/client/assets/admin.html'
		})
	],
	devtool: 'source-map'
};
<|endoftext|>


<commit_before>'use strict';

/**
 * Module dependencies.
 */
var mongoose = require('mongoose'),
	errorHandler = require('./errors.server.controller'),
	List = mongoose.model('List'),
	Users = mongoose.model('User'),
	_ = require('lodash');

/**
 * Reads all the sublists for the given list
 */
exports.getLists = function(req, res) {
	List.find().populate('user', 'username').exec(function(err, lists) {
		if (err) {
			return res.status(400).send({
				message: errorHandler.getErrorMessage(err)
			});
		} else {
			res.json(lists);
		}
	});
};

/**
 * Creates a list for the current username
 */
exports.create = function(req, res) {
	var list = new List(req.body);
	list.user = req.user;

	// For some reason the server likes to insert escape characters here, so we
	// must remove them manually. Step 1, convert to string.
	var workingJson = JSON.stringify(list.access);

	// Removing all backslashes, they can't be in emails.
	workingJson = workingJson.replace("\\", "");

	// Removing the first and second-to-last character; these are unnecessary
	// quotes.
	workingJson = workingJson.replace("\"\"", "\"");

	list.access = JSON.parse(workingJson);

	list.save(function(err) {
		if (err) {
			return res.status(400).send({
				message: errorHandler.getErrorMessage(err)
			});
		} else {
			res.json(list);
		}
	});
};

/**
 * Update a list by ID
 */
exports.update = function(req, res) {
	var list = req.list;

 	list = _.extend(list, req.body);

	list.save(function(err) {
		if (err) {
			return res.status(400).send({
				message: errorHandler.getErrorMessage(err)
			});
		} else {
			res.json(list);
		}
	});
};

/**
 * Remove a list by ID
 */
exports.remove = function(req, res) {
	var list = req.list;

	list.remove(function(err) {
		if (err) {
			return res.status(400).send({
				message: errorHandler.getErrorMessage(err)
			});
		} else {
			res.json(list);
		}
	});
};

exports.rootID = function(req, res, username) {
	Users.find().exec(function(err, users) {
		if (err) {
			return res.status(404).send({
				message: 'Could not find any users'
			});
		}
		// Array of references to all root lists
		var allUsers = users.map(function(user) { return user._id; });

		List.findOne({$and: [{user: {$in: allUsers}}, {root: true}]}, function(err, doc) {
			if (err) {
				return res.status(404).send({
					message: 'Root list not found'
				});
			}
			res.send(doc._id);
		});
	});
};

/**
 * Gets a single List based on its ID
 */
exports.getListByID = function(req, res, next, id) {
	if (!mongoose.Types.ObjectId.isValid(id)) {
		return res.status(400).send({
			message: 'Requested list is invalid'
		});
	}

	List.findById(id).exec(function(err, list) {
		if (err) return next(err);
		if (!list) {
			return res.status(404).send({
				message: 'List not found'
			});
		}
		req.list = list;
		next();
	});
};

/**
 * Returns the current level of authorization of the validated user
 */
exports.hasAuthorization = function(req, res, next) {

	next();
};
<commit_msg>Forgot to check for null<commit_after>'use strict';

/**
 * Module dependencies.
 */
var mongoose = require('mongoose'),
	errorHandler = require('./errors.server.controller'),
	List = mongoose.model('List'),
	Users = mongoose.model('User'),
	_ = require('lodash');

/**
 * Reads all the sublists for the given list
 */
exports.getLists = function(req, res) {
	List.find().populate('user', 'username').exec(function(err, lists) {
		if (err) {
			return res.status(400).send({
				message: errorHandler.getErrorMessage(err)
			});
		} else {
			res.json(lists);
		}
	});
};

/**
 * Creates a list for the current username
 */
exports.create = function(req, res) {
	var list = new List(req.body);
	list.user = req.user;

	// For some reason the server likes to insert escape characters here, so we
	// must remove them manually. Step 1, convert to string.
	var workingJson = JSON.stringify(list.access);

	// Removing all backslashes, they can't be in emails.
	workingJson = workingJson.replace("\\", "");

	// Removing the first and second-to-last character; these are unnecessary
	// quotes.
	workingJson = workingJson.replace("\"\"", "\"");

	list.access = JSON.parse(workingJson);

	list.save(function(err) {
		if (err) {
			return res.status(400).send({
				message: errorHandler.getErrorMessage(err)
			});
		} else {
			res.json(list);
		}
	});
};

/**
 * Update a list by ID
 */
exports.update = function(req, res) {
	var list = req.list;

 	list = _.extend(list, req.body);

	list.save(function(err) {
		if (err) {
			return res.status(400).send({
				message: errorHandler.getErrorMessage(err)
			});
		} else {
			res.json(list);
		}
	});
};

/**
 * Remove a list by ID
 */
exports.remove = function(req, res) {
	var list = req.list;

	list.remove(function(err) {
		if (err) {
			return res.status(400).send({
				message: errorHandler.getErrorMessage(err)
			});
		} else {
			res.json(list);
		}
	});
};

exports.rootID = function(req, res, username) {
	Users.find().exec(function(err, users) {
		if (err) {
			return res.status(404).send({
				message: 'Could not find any users'
			});
		}
		// Array of references to all root lists
		var allUsers = users.map(function(user) { return user._id; });

		List.findOne({$and: [{user: {$in: allUsers}}, {root: true}]}, function(err, doc) {
			if (err || doc == null) {
				return res.status(404).send({
					message: 'Root list not found'
				});
			}
			res.send(doc._id);
		});
	});
};

/**
 * Gets a single List based on its ID
 */
exports.getListByID = function(req, res, next, id) {
	if (!mongoose.Types.ObjectId.isValid(id)) {
		return res.status(400).send({
			message: 'Requested list is invalid'
		});
	}

	List.findById(id).exec(function(err, list) {
		if (err) return next(err);
		if (!list) {
			return res.status(404).send({
				message: 'List not found'
			});
		}
		req.list = list;
		next();
	});
};

/**
 * Returns the current level of authorization of the validated user
 */
exports.hasAuthorization = function(req, res, next) {

	next();
};
<|endoftext|>


<commit_before>import * as watif from '../utils/is';
import render from '../utils/render';
import { $ } from '../utils/query';
import HASH from '../hash';

class PageConsoleDefault {
  constructor() {
  }

  init() {
    let global = window;

    this.origin = {
      log: global.console.log,
      error: global.console.error,
      warn: global.console.warn,
      info: global.console.info,
      debug: global.console.debug
    };

    global.console.log = (...args) => {
      this.print({
        type: 'log',
        content: args
      });
    };
    global.console.error = (...args) => {
      this.print({
        type: 'error',
        content: args
      });
    };
    global.console.warn = (...args) => {
      this.print({
        type: 'warn',
        content: args
      });
    };
    global.console.info = (...args) => {
      this.print({
        type: 'info',
        content: args
      });
    };
    global.console.debug = (...args) => {
      this.print({
        type: 'debug',
        content: args
      });
    };
  }

  print(opt) {
    let panel = $(`#_page-console-${HASH}-console-panel`);
    let output = [];
    let content = Array.prototype.slice.call(opt.content);

    for (let i = 0, len = opt.content.length; i < len; i++) {
      let item = opt.content[i];
      try {
        if (watif.isFunction(item)) {
          output.push(item.toString());
        } else if (watif.isArray(item)) {
          output.push(this.formatArray(item));
        } else if (watif.isObject(item)) {

        } else { // default string
          output.push(item);
        }
      } catch (err) {

      }
    }

    // this.origin.log.call(window.console, opt);

    let dom = render({
      type: opt.type,
      content: output
    });
    panel.appendChild(dom);

    if (typeof this.origin[opt.type] === 'function') {
      this.origin[opt.type].apply(window.console, content);
    }
  }

  formatArray(arr) {
    return `[${arr.toString()}]`;
  }
}

let defaultConsole = new PageConsoleDefault();

export default defaultConsole;
<commit_msg>formatObject<commit_after>import * as watif from '../utils/is';
import render from '../utils/render';
import { $ } from '../utils/query';
import HASH from '../hash';

class PageConsoleDefault {
  constructor() {
  }

  init() {
    let global = window;

    this.origin = {
      log: global.console.log,
      error: global.console.error,
      warn: global.console.warn,
      info: global.console.info,
      debug: global.console.debug
    };

    global.console.log = (...args) => {
      this.print({
        type: 'log',
        content: args
      });
    };
    global.console.error = (...args) => {
      this.print({
        type: 'error',
        content: args
      });
    };
    global.console.warn = (...args) => {
      this.print({
        type: 'warn',
        content: args
      });
    };
    global.console.info = (...args) => {
      this.print({
        type: 'info',
        content: args
      });
    };
    global.console.debug = (...args) => {
      this.print({
        type: 'debug',
        content: args
      });
    };
  }

  print(opt) {
    let panel = $(`#_page-console-${HASH}-console-panel`);
    let output = [];
    let content = Array.prototype.slice.call(opt.content);

    for (let i = 0, len = opt.content.length; i < len; i++) {
      let item = opt.content[i];
      try {
        if (watif.isFunction(item)) {
          output.push(item.toString());
        } else if (watif.isArray(item)) {
          output.push(this.formatArray(item));
        } else if (watif.isObject(item)) {
          output.push(this.formatObject(item));
        } else { // default string
          output.push(item);
        }
      } catch (err) {

      }
    }

    // this.origin.log.call(window.console, opt);

    let dom = render({
      type: opt.type,
      content: output
    });
    panel.appendChild(dom);

    if (typeof this.origin[opt.type] === 'function') {
      this.origin[opt.type].apply(window.console, content);
    }
  }

  formatArray(arr) {
    return `[${arr.toString()}]`;
  }

  formatObject(obj) {
    let objStr = JSON.stringify(obj);
  }
}

let defaultConsole = new PageConsoleDefault();

export default defaultConsole;
<|endoftext|>


<commit_before>var actions = require('actions')
var _ = require('lodash')

var roleSettler = {
    run: function(creep) {

        var dest = Game.flags.expansionTarget;

        if(creep.room.name != dest.pos.room) {
            console.log(dest.pos.room);
            console.log(dest)
            console.log(dest.pos)
            console.log(dest.room)
            creep.moveTo(dest);
        } else {

            if(creep.carry.energy == 0) {
                creep.memory.state = 'settlerHarvesting';
            }

            var state = creep.memory.state;

            if(state == 'deciding') {
                actions.newJob(creep);
                state = creep.memory.state;
            }

            if(state == 'settlerHarvesting') {
                actions.workerHarvest(creep);
            } else if(state == 'upgrading') {
                actions.upgrade(creep);
            } else if(state == 'storing') {
                actions.storeEnergy(creep);
            } else if(state == 'building') {
                actions.build(creep);
            } else if(state == 'repairing') {
                actions.repair(creep);
            }

        }

    }
};

module.exports = roleSettler;
<commit_msg>name fix<commit_after>var actions = require('actions')
var _ = require('lodash')

var roleSettler = {
    run: function(creep) {

        var dest = Game.flags.expansionTarget;

        if(creep.room.name != dest.room.name) {
            console.log(dest.pos.room);
            console.log(dest)
            console.log(dest.pos)
            console.log(dest.room)
            creep.moveTo(dest);
        } else {

            if(creep.carry.energy == 0) {
                creep.memory.state = 'settlerHarvesting';
            }

            var state = creep.memory.state;

            if(state == 'deciding') {
                actions.newJob(creep);
                state = creep.memory.state;
            }

            if(state == 'settlerHarvesting') {
                actions.workerHarvest(creep);
            } else if(state == 'upgrading') {
                actions.upgrade(creep);
            } else if(state == 'storing') {
                actions.storeEnergy(creep);
            } else if(state == 'building') {
                actions.build(creep);
            } else if(state == 'repairing') {
                actions.repair(creep);
            }

        }

    }
};

module.exports = roleSettler;
<|endoftext|>


<commit_before>// Tracking categories.
export const VIDEO_CATEGORY = 'Discovery Video';
export const NAVIGATION_CATEGORY = 'Discovery Navigation';

// Action types.
export const DISCO_RESULTS = 'DISCO_RESULTS';

// Keys for extensions and theme data in the discovery pane JSON blob.
export const DISCO_DATA_THEME = 'theme';
export const DISCO_DATA_EXTENSION = 'extension';
export const DISCO_DATA_UNKNOWN = 'unknown';
// Built-in extensions and themes to ignore.
export const DISCO_DATA_GUID_IGNORE_LIST = [
  '{972ce4c6-7e08-4474-a285-3208198ce6fd}', // Default theme
  'firefox-compact-light@mozilla.org@personas.mozilla.org', // Default Compact Light theme
  'firefox-compact-dark@mozilla.org@personas.mozilla.org', // Default Compact Dark theme
  'e10srollout@mozilla.org', // e10s
  'firefox@getpocket.com', // Pocket
  'loop@mozilla.org', // Firefox Hello
  'aushelper@mozilla.org', // Application Update Service Helper
  'webcompat@mozilla.org', // Web Compat
  'flyweb@mozilla.org', // FlyWeb
  'formautofill@mozilla.org', // Form Autofill
  'presentation@mozilla.org', // Presentation
  'shield-recipe-client@mozilla.org', // Shield Recipe Client
  'webcompat-reporter@mozilla.org', // WebCompat Reporter
  'disableSHA1rollout@mozilla.org', // SHA-1 deprecation staged rollout
  'hsts-priming@mozilla.org', // Send HSTS Priming Requests
  'd3d9fallback@mozilla.org', // D3D9 Acceleration Fallback
  'asyncrendering@mozilla.org', // Asynchronous Plugin Rendering
  'brotli@mozilla.org', // Disable Brotli on Firefox 44, 45
  'diagnostics@mozilla.org', // Diagnose Firefox update problems
  'malware-remediation@mozilla.org', // Youtube Unblocker Remediation
  'outofdate-notifications@mozilla.org', // Firefox out of date notifications
  'websensehelper@mozilla.org', // Websense Helper
  'tls13-compat-ff51@mozilla.org', // TLS 1.3 Compatibility Testing
  'tls13-comparison-all-v1@mozilla.org', // TLS 1.3 A/B Test Experiment
  'deployment-checker@mozilla.org', // Site Deployment Checker
  'screenshots@mozilla.org', // Firefox Screenshots
  'disable-prefetch@mozilla.org', // Disable Prefetch
  'activity-stream@mozilla.org', // Activity Stream
  'disable-cert-transparency@mozilla.org', // Disable TLS Certificate Transparency
  'disable-ocsp-stapling@mozilla.org', // Disable OCSP Stapling
  'onboarding@mozilla.org', // Photon onboarding
  'followonsearch@mozilla.com', // Follow-on Search Telemetry
  'clicktoplay-rollout@mozilla.org', // Click to Play Rollout
  'tls13-middlebox@mozilla.org', // TLS 1.3 Compatibility Testing of Middleboxes
];
<commit_msg>Remove trailing spaces to fix lint<commit_after>// Tracking categories.
export const VIDEO_CATEGORY = 'Discovery Video';
export const NAVIGATION_CATEGORY = 'Discovery Navigation';

// Action types.
export const DISCO_RESULTS = 'DISCO_RESULTS';

// Keys for extensions and theme data in the discovery pane JSON blob.
export const DISCO_DATA_THEME = 'theme';
export const DISCO_DATA_EXTENSION = 'extension';
export const DISCO_DATA_UNKNOWN = 'unknown';
// Built-in extensions and themes to ignore.
export const DISCO_DATA_GUID_IGNORE_LIST = [
  '{972ce4c6-7e08-4474-a285-3208198ce6fd}', // Default theme
  'firefox-compact-light@mozilla.org@personas.mozilla.org', // Default Compact Light theme
  'firefox-compact-dark@mozilla.org@personas.mozilla.org', // Default Compact Dark theme
  'e10srollout@mozilla.org', // e10s
  'firefox@getpocket.com', // Pocket
  'loop@mozilla.org', // Firefox Hello
  'aushelper@mozilla.org', // Application Update Service Helper
  'webcompat@mozilla.org', // Web Compat
  'flyweb@mozilla.org', // FlyWeb
  'formautofill@mozilla.org', // Form Autofill
  'presentation@mozilla.org', // Presentation
  'shield-recipe-client@mozilla.org', // Shield Recipe Client
  'webcompat-reporter@mozilla.org', // WebCompat Reporter
  'disableSHA1rollout@mozilla.org', // SHA-1 deprecation staged rollout
  'hsts-priming@mozilla.org', // Send HSTS Priming Requests
  'd3d9fallback@mozilla.org', // D3D9 Acceleration Fallback
  'asyncrendering@mozilla.org', // Asynchronous Plugin Rendering
  'brotli@mozilla.org', // Disable Brotli on Firefox 44, 45
  'diagnostics@mozilla.org', // Diagnose Firefox update problems
  'malware-remediation@mozilla.org', // Youtube Unblocker Remediation
  'outofdate-notifications@mozilla.org', // Firefox out of date notifications
  'websensehelper@mozilla.org', // Websense Helper
  'tls13-compat-ff51@mozilla.org', // TLS 1.3 Compatibility Testing
  'tls13-comparison-all-v1@mozilla.org', // TLS 1.3 A/B Test Experiment
  'deployment-checker@mozilla.org', // Site Deployment Checker
  'screenshots@mozilla.org', // Firefox Screenshots
  'disable-prefetch@mozilla.org', // Disable Prefetch
  'activity-stream@mozilla.org', // Activity Stream
  'disable-cert-transparency@mozilla.org', // Disable TLS Certificate Transparency
  'disable-ocsp-stapling@mozilla.org', // Disable OCSP Stapling
  'onboarding@mozilla.org', // Photon onboarding
  'followonsearch@mozilla.com', // Follow-on Search Telemetry
  'clicktoplay-rollout@mozilla.org', // Click to Play Rollout
  'tls13-middlebox@mozilla.org', // TLS 1.3 Compatibility Testing of Middleboxes
];
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import {
  StyleSheet,
  Text,
  View,
  Image,
  TouchableNativeFeedback
} from 'react-native';

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5,
  },
});

export default class MyHome extends Component {

  state = {}

  constructor(props) {
    super(props)
    this.state.to_map_screen = props.to_map_screen
  }

  render() {
    return(
      <View style={styles.container}>
          <Text style={styles.welcome}>
            Welcome to React Native!
          </Text>
          <TouchableNativeFeedback onPress={() => this.setState({screen: "map"})}
          background={TouchableNativeFeedback.SelectableBackgroundBorderless()}
          style={{borderRadius: 100}}>
            <View style={{width: 150, height: 150, backgroundColor: 'green', borderRadius: 100}}>
              <Image
              style={{width: 150, height: 150, borderRadius: 100}}
              source={require('../../img/play-button.png')}
              />
            </View>
          </TouchableNativeFeedback>
        </View>
    )
  }
}<commit_msg>Added audio functions. Play button not hooked up yet.<commit_after>import React, { Component } from 'react';
import {
  StyleSheet,
  Text,
  View,
  Image,
  TouchableNativeFeedback
} from 'react-native';

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5,
  },
});

const Sound = require('react-native-sound');
var curSong = '';	//This is where the current/next song is put.
					//Note, song playing won't update until change is called

export default class MyHome extends Component {

  state = {}

  constructor(props) {
    super(props);
    this.state.to_map_screen = props.to_map_screen;
	this.state.loopingSound = undefined;

	Sound.setCategory('Ambient', true);

	this.playSoundLooped = () => {
		if (this.state.loopingSound) {
			return;
		}
		const s = new Sound(curSong, Sound.MAIN_BUNDLE, (e) => {
			if (e) {
				console.log('error', e);
			}
			s.setNumberOfLoops(-1);
			s.play();
		});
		this.setState({loopingSound: s});
	};

	this.stopSoundLooped = () => {
		if (!this.state.loopingSound) {
			return;
		}
		this.state.loopingSound
			.stop()
			.release();
		this.setState({loopingSound:null});
	};

	this.changed = () => {
		if (!this.state.loopingSound) {
			return;
		}
		this.state.loopingSound
			.stop()
			.release();
		this.setState({loopingSound:null});

		const s = new Sound(curSong, Sound.MAIN_BUNDLE, (e) => {
			if (e) {
				console.log('error', e);
			}
			s.setNumberOfLoops(-1);
			s.play();
		});
		this.setState({loopingSound:s});
	};

//	this.state = {
//		loopingSound: undefined,
//	};
  }

  render() {
    return(
      <View style={styles.container}>
          <Text style={styles.welcome}>
            Welcome to React Native!
          </Text>
          <TouchableNativeFeedback onPress={() => this.setState({screen: "map"})}
          background={TouchableNativeFeedback.SelectableBackgroundBorderless()}
          style={{borderRadius: 100}}>
            <View style={{width: 150, height: 150, backgroundColor: 'green', borderRadius: 100}}>
              <Image
              style={{width: 150, height: 150, borderRadius: 100}}
              source={require('../../img/play-button.png')}
              />
            </View>
          </TouchableNativeFeedback>
        </View>
    )
  }
}<|endoftext|>


<commit_before>// ==========================================================================
// Project:   SproutCore - JavaScript Application Framework
// Copyright: ©2006-2010 Sprout Systems, Inc. and contributors.
//            Portions ©2008-2010 Apple Inc. All rights reserved.
// License:   Licensed under MIT license (see license.js)
// ==========================================================================

sc_require('data_sources/data_source');
sc_require('models/record');

/** @class

  TODO: Describe Class

  @extends SC.DataSource
  @since SproutCore 1.0
*/
SC.FixturesDataSource = SC.DataSource.extend(
  /** @scope SC.FixturesDataSource.prototype */ {

  /**
    If YES then the data source will asyncronously respond to data requests
    from the server.  If you plan to replace the fixture data source with a
    data source that talks to a real remote server (using Ajax for example),
    you should leave this property set to YES so that Fixtures source will
    more accurately simulate your remote data source.

    If you plan to replace this data source with something that works with
    local storage, for example, then you should set this property to NO to
    accurately simulate the behavior of your actual data source.

    @property {Boolean}
  */
  simulateRemoteResponse: NO,

  /**
    If you set simulateRemoteResponse to YES, then the fixtures soure will
    assume a response latency from your server equal to the msec specified
    here.  You should tune this to simulate latency based on the expected
    performance of your server network.  Here are some good guidelines:

    - 500: Simulates a basic server written in PHP, Ruby, or Python (not twisted) without a CDN in front for caching.
    - 250: (Default) simulates the average latency needed to go back to your origin server from anywhere in the world.  assumes your servers itself will respond to requests < 50 msec
    - 100: simulates the latency to a "nearby" server (i.e. same part of the world).  Suitable for simulating locally hosted servers or servers with multiple data centers around the world.
    - 50: simulates the latency to an edge cache node when using a CDN.  Life is really good if you can afford this kind of setup.

    @property {Number}
  */
  latency: 50,

  // ..........................................................
  // CANCELLING
  //

  /** @private */
  cancel: function(store, storeKeys) {
    return NO;
  },

  // ..........................................................
  // FETCHING
  //

  /** @private */
  fetch: function(store, query) {

    // can only handle local queries out of the box
    if (query.get('location') !== SC.Query.LOCAL) {
      throw SC.$error('SC.Fixture data source can only fetch local queries');
    }

    if (!query.get('recordType') && !query.get('recordTypes')) {
      throw SC.$error('SC.Fixture data source can only fetch queries with one or more record types');
    }

    if (this.get('simulateRemoteResponse')) {
      this.invokeLater(this._fetch, this.get('latency'), store, query);

    } else this._fetch(store, query);
  },

  /** @private
    Actually performs the fetch.
  */
  _fetch: function(store, query) {

    // NOTE: Assumes recordType or recordTypes is defined.  checked in fetch()
    var recordType = query.get('recordType'),
        recordTypes = query.get('recordTypes') || [recordType];

    // load fixtures for each recordType
    recordTypes.forEach(function(recordType) {
      if (SC.typeOf(recordType) === SC.T_STRING) {
        recordType = SC.objectForPropertyPath(recordType);
      }

      if (recordType) this.loadFixturesFor(store, recordType);
    }, this);

    // notify that query has now loaded - puts it into a READY state
    store.dataSourceDidFetchQuery(query);
  },

  // ..........................................................
  // RETRIEVING
  //

  /** @private */
  retrieveRecords: function(store, storeKeys) {
    // first let's see if the fixture data source can handle any of the
    // storeKeys
    var latency = this.get('latency'),
        ret     = this.hasFixturesFor(storeKeys) ;
    if (!ret) return ret ;

    if (this.get('simulateRemoteResponse')) {
      this.invokeLater(this._retrieveRecords, latency, store, storeKeys);
    } else this._retrieveRecords(store, storeKeys);

    return ret ;
  },

  _retrieveRecords: function(store, storeKeys) {

    storeKeys.forEach(function(storeKey) {
      var ret        = [],
          recordType = SC.Store.recordTypeFor(storeKey),
          id         = store.idFor(storeKey),
          hash       = this.fixtureForStoreKey(store, storeKey);
      ret.push(storeKey);
      store.dataSourceDidComplete(storeKey, hash, id);
    }, this);
  },

  // ..........................................................
  // UPDATE
  //

  /** @private */
  updateRecords: function(store, storeKeys, params) {
    // first let's see if the fixture data source can handle any of the
    // storeKeys
    var latency = this.get('latency'),
        ret     = this.hasFixturesFor(storeKeys) ;
    if (!ret) return ret ;

    if (this.get('simulateRemoteResponse')) {
      this.invokeLater(this._updateRecords, latency, store, storeKeys);
    } else this._updateRecords(store, storeKeys);

    return ret ;
  },

  _updateRecords: function(store, storeKeys) {
    storeKeys.forEach(function(storeKey) {
      var hash = store.readDataHash(storeKey);
      this.setFixtureForStoreKey(store, storeKey, hash);
      store.dataSourceDidComplete(storeKey);
    }, this);
  },

  // ..........................................................
  // CREATE RECORDS
  //

  /** @private */
  createRecords: function(store, storeKeys, params) {
    // first let's see if the fixture data source can handle any of the
    // storeKeys
    var latency = this.get('latency');

    if (this.get('simulateRemoteResponse')) {
      this.invokeLater(this._createRecords, latency, store, storeKeys);
    } else this._createRecords(store, storeKeys);

    return YES ;
  },

  _createRecords: function(store, storeKeys) {
    storeKeys.forEach(function(storeKey) {
      var id         = store.idFor(storeKey),
          recordType = store.recordTypeFor(storeKey),
          dataHash   = store.readDataHash(storeKey),
          fixtures   = this.fixturesFor(recordType);

      if (!id) id = this.generateIdFor(recordType, dataHash, store, storeKey);
      this._invalidateCachesFor(recordType, storeKey, id);
      fixtures[id] = dataHash;

      store.dataSourceDidComplete(storeKey, null, id);
    }, this);
  },

  // ..........................................................
  // DESTROY RECORDS
  //

  /** @private */
  destroyRecords: function(store, storeKeys, params) {
    // first let's see if the fixture data source can handle any of the
    // storeKeys
    var latency = this.get('latency'),
        ret     = this.hasFixturesFor(storeKeys) ;
    if (!ret) return ret ;

    if (this.get('simulateRemoteResponse')) {
      this.invokeLater(this._destroyRecords, latency, store, storeKeys);
    } else this._destroyRecords(store, storeKeys);

    return ret ;
  },

  _destroyRecords: function(store, storeKeys) {
    storeKeys.forEach(function(storeKey) {
      var id         = store.idFor(storeKey),
          recordType = store.recordTypeFor(storeKey),
          fixtures   = this.fixturesFor(recordType);

      this._invalidateCachesFor(recordType, storeKey, id);
      if (id) delete fixtures[id];
      store.dataSourceDidDestroy(storeKey);
    }, this);
  },

  // ..........................................................
  // INTERNAL METHODS/PRIMITIVES
  //

  /**
    Load fixtures for a given fetchKey into the store
    and push it to the ret array.

    @param {SC.Store} store the store to load into
    @param {SC.Record} recordType the record type to load
    @param {SC.Array} ret is passed, array to add loaded storeKeys to.
    @returns {SC.Fixture} receiver
  */
  loadFixturesFor: function(store, recordType, ret) {
    var hashes   = [],
        dataHashes, i, storeKey ;

    dataHashes = this.fixturesFor(recordType);

    for(i in dataHashes){
      storeKey = recordType.storeKeyFor(i);
      if (store.peekStatus(storeKey) === SC.Record.EMPTY) {
        hashes.push(dataHashes[i]);
      }
      if (ret) ret.push(storeKey);
    }

    // only load records that were not already loaded to avoid infinite loops
    if (hashes && hashes.length>0) store.loadRecords(recordType, hashes);

    return this ;
  },

  /**
    Generates an id for the passed record type.  You can override this if
    needed.  The default generates a storekey and formats it as a string.

    @param {Class} recordType Subclass of SC.Record
    @param {Hash} dataHash the data hash for the record
    @param {SC.Store} store the store
    @param {Number} storeKey store key for the item
    @returns {String}
  */
  generateIdFor: function(recordType, dataHash, store, storeKey) {
    return "@id%@".fmt(SC.Store.generateStoreKey());
  },

  /**
    Based on the storeKey it returns the specified fixtures

    @param {SC.Store} store the store
    @param {Number} storeKey the storeKey
    @returns {Hash} data hash or null
  */
  fixtureForStoreKey: function(store, storeKey) {
    var id         = store.idFor(storeKey),
        recordType = store.recordTypeFor(storeKey),
        fixtures   = this.fixturesFor(recordType);
    return fixtures ? fixtures[id] : null;
  },

  /**
    Update the data hash fixture for the named store key.

    @param {SC.Store} store the store
    @param {Number} storeKey the storeKey
    @param {Hash} dataHash
    @returns {SC.FixturesDataSource} receiver
  */
  setFixtureForStoreKey: function(store, storeKey, dataHash) {
    var id         = store.idFor(storeKey),
        recordType = store.recordTypeFor(storeKey),
        fixtures   = this.fixturesFor(recordType);
    this._invalidateCachesFor(recordType, storeKey, id);
    fixtures[id] = dataHash;
    return this ;
  },

  /**
    Get the fixtures for the passed record type and prepare them if needed.
    Return cached value when complete.

    @param {SC.Record} recordType
    @returns {Hash} data hashes
  */
  fixturesFor: function(recordType) {
    // get basic fixtures hash.
    if (!this._fixtures) this._fixtures = {};
    var fixtures = this._fixtures[SC.guidFor(recordType)];
    if (fixtures) return fixtures ;

    // need to load fixtures.
    var dataHashes = recordType ? recordType.FIXTURES : null,
        len        = dataHashes ? dataHashes.length : 0,
        primaryKey = recordType ? recordType.prototype.primaryKey : 'guid',
        idx, dataHash, id ;

    this._fixtures[SC.guidFor(recordType)] = fixtures = {} ;
    for(idx=0;idx<len;idx++) {
      dataHash = dataHashes[idx];
      id = dataHash[primaryKey];
      if (!id) id = this.generateIdFor(recordType, dataHash);
      fixtures[id] = dataHash;
    }
    return fixtures;
  },

  /**
    Returns YES if fixtures for a given recordType have already been loaded

    @param {SC.Record} recordType
    @returns {Boolean} storeKeys
  */
  fixturesLoadedFor: function(recordType) {
    if (!this._fixtures) return NO;
    var ret = [], fixtures = this._fixtures[SC.guidFor(recordType)];
    return fixtures ? YES: NO;
  },

  /**
    Returns YES or SC.MIXED_STATE if one or more of the storeKeys can be
    handled by the fixture data source.

    @param {Array} storeKeys the store keys
    @returns {Boolean} YES if all handled, MIXED_STATE if some handled
  */
  hasFixturesFor: function(storeKeys) {
    var ret = NO ;
    storeKeys.forEach(function(storeKey) {
      if (ret !== SC.MIXED_STATE) {
        var recordType = SC.Store.recordTypeFor(storeKey),
            fixtures   = recordType ? recordType.FIXTURES : null ;
        if (fixtures && fixtures.length && fixtures.length>0) {
          if (ret === NO) ret = YES ;
        } else if (ret === YES) ret = SC.MIXED_STATE ;
      }
    }, this);

    return ret ;
  },

  /** @private
    Invalidates any internal caches based on the recordType and optional
    other parameters.  Currently this only invalidates the storeKeyCache used
    for fetch, but it could invalidate others later as well.

    @param {SC.Record} recordType the type of record modified
    @param {Number} storeKey optional store key
    @param {String} id optional record id
    @returns {SC.FixturesDataSource} receiver
  */
  _invalidateCachesFor: function(recordType, storeKey, id) {
    var cache = this._storeKeyCache;
    if (cache) delete cache[SC.guidFor(recordType)];
    return this ;
  }

});

/**
  Default fixtures instance for use in applications.

  @property {SC.FixturesDataSource}
*/
SC.Record.fixtures = SC.FixturesDataSource.create();
<commit_msg>Fixed typo<commit_after>// ==========================================================================
// Project:   SproutCore - JavaScript Application Framework
// Copyright: ©2006-2010 Sprout Systems, Inc. and contributors.
//            Portions ©2008-2010 Apple Inc. All rights reserved.
// License:   Licensed under MIT license (see license.js)
// ==========================================================================

sc_require('data_sources/data_source');
sc_require('models/record');

/** @class

  TODO: Describe Class

  @extends SC.DataSource
  @since SproutCore 1.0
*/
SC.FixturesDataSource = SC.DataSource.extend(
  /** @scope SC.FixturesDataSource.prototype */ {

  /**
    If YES then the data source will asynchronously respond to data requests
    from the server.  If you plan to replace the fixture data source with a
    data source that talks to a real remote server (using Ajax for example),
    you should leave this property set to YES so that Fixtures source will
    more accurately simulate your remote data source.

    If you plan to replace this data source with something that works with
    local storage, for example, then you should set this property to NO to
    accurately simulate the behavior of your actual data source.

    @property {Boolean}
  */
  simulateRemoteResponse: NO,

  /**
    If you set simulateRemoteResponse to YES, then the fixtures source will
    assume a response latency from your server equal to the msec specified
    here.  You should tune this to simulate latency based on the expected
    performance of your server network.  Here are some good guidelines:

    - 500: Simulates a basic server written in PHP, Ruby, or Python (not twisted) without a CDN in front for caching.
    - 250: (Default) simulates the average latency needed to go back to your origin server from anywhere in the world.  assumes your servers itself will respond to requests < 50 msec
    - 100: simulates the latency to a "nearby" server (i.e. same part of the world).  Suitable for simulating locally hosted servers or servers with multiple data centers around the world.
    - 50: simulates the latency to an edge cache node when using a CDN.  Life is really good if you can afford this kind of setup.

    @property {Number}
  */
  latency: 50,

  // ..........................................................
  // CANCELLING
  //

  /** @private */
  cancel: function(store, storeKeys) {
    return NO;
  },

  // ..........................................................
  // FETCHING
  //

  /** @private */
  fetch: function(store, query) {

    // can only handle local queries out of the box
    if (query.get('location') !== SC.Query.LOCAL) {
      throw SC.$error('SC.Fixture data source can only fetch local queries');
    }

    if (!query.get('recordType') && !query.get('recordTypes')) {
      throw SC.$error('SC.Fixture data source can only fetch queries with one or more record types');
    }

    if (this.get('simulateRemoteResponse')) {
      this.invokeLater(this._fetch, this.get('latency'), store, query);

    } else this._fetch(store, query);
  },

  /** @private
    Actually performs the fetch.
  */
  _fetch: function(store, query) {

    // NOTE: Assumes recordType or recordTypes is defined.  checked in fetch()
    var recordType = query.get('recordType'),
        recordTypes = query.get('recordTypes') || [recordType];

    // load fixtures for each recordType
    recordTypes.forEach(function(recordType) {
      if (SC.typeOf(recordType) === SC.T_STRING) {
        recordType = SC.objectForPropertyPath(recordType);
      }

      if (recordType) this.loadFixturesFor(store, recordType);
    }, this);

    // notify that query has now loaded - puts it into a READY state
    store.dataSourceDidFetchQuery(query);
  },

  // ..........................................................
  // RETRIEVING
  //

  /** @private */
  retrieveRecords: function(store, storeKeys) {
    // first let's see if the fixture data source can handle any of the
    // storeKeys
    var latency = this.get('latency'),
        ret     = this.hasFixturesFor(storeKeys) ;
    if (!ret) return ret ;

    if (this.get('simulateRemoteResponse')) {
      this.invokeLater(this._retrieveRecords, latency, store, storeKeys);
    } else this._retrieveRecords(store, storeKeys);

    return ret ;
  },

  _retrieveRecords: function(store, storeKeys) {

    storeKeys.forEach(function(storeKey) {
      var ret        = [],
          recordType = SC.Store.recordTypeFor(storeKey),
          id         = store.idFor(storeKey),
          hash       = this.fixtureForStoreKey(store, storeKey);
      ret.push(storeKey);
      store.dataSourceDidComplete(storeKey, hash, id);
    }, this);
  },

  // ..........................................................
  // UPDATE
  //

  /** @private */
  updateRecords: function(store, storeKeys, params) {
    // first let's see if the fixture data source can handle any of the
    // storeKeys
    var latency = this.get('latency'),
        ret     = this.hasFixturesFor(storeKeys) ;
    if (!ret) return ret ;

    if (this.get('simulateRemoteResponse')) {
      this.invokeLater(this._updateRecords, latency, store, storeKeys);
    } else this._updateRecords(store, storeKeys);

    return ret ;
  },

  _updateRecords: function(store, storeKeys) {
    storeKeys.forEach(function(storeKey) {
      var hash = store.readDataHash(storeKey);
      this.setFixtureForStoreKey(store, storeKey, hash);
      store.dataSourceDidComplete(storeKey);
    }, this);
  },

  // ..........................................................
  // CREATE RECORDS
  //

  /** @private */
  createRecords: function(store, storeKeys, params) {
    // first let's see if the fixture data source can handle any of the
    // storeKeys
    var latency = this.get('latency');

    if (this.get('simulateRemoteResponse')) {
      this.invokeLater(this._createRecords, latency, store, storeKeys);
    } else this._createRecords(store, storeKeys);

    return YES ;
  },

  _createRecords: function(store, storeKeys) {
    storeKeys.forEach(function(storeKey) {
      var id         = store.idFor(storeKey),
          recordType = store.recordTypeFor(storeKey),
          dataHash   = store.readDataHash(storeKey),
          fixtures   = this.fixturesFor(recordType);

      if (!id) id = this.generateIdFor(recordType, dataHash, store, storeKey);
      this._invalidateCachesFor(recordType, storeKey, id);
      fixtures[id] = dataHash;

      store.dataSourceDidComplete(storeKey, null, id);
    }, this);
  },

  // ..........................................................
  // DESTROY RECORDS
  //

  /** @private */
  destroyRecords: function(store, storeKeys, params) {
    // first let's see if the fixture data source can handle any of the
    // storeKeys
    var latency = this.get('latency'),
        ret     = this.hasFixturesFor(storeKeys) ;
    if (!ret) return ret ;

    if (this.get('simulateRemoteResponse')) {
      this.invokeLater(this._destroyRecords, latency, store, storeKeys);
    } else this._destroyRecords(store, storeKeys);

    return ret ;
  },

  _destroyRecords: function(store, storeKeys) {
    storeKeys.forEach(function(storeKey) {
      var id         = store.idFor(storeKey),
          recordType = store.recordTypeFor(storeKey),
          fixtures   = this.fixturesFor(recordType);

      this._invalidateCachesFor(recordType, storeKey, id);
      if (id) delete fixtures[id];
      store.dataSourceDidDestroy(storeKey);
    }, this);
  },

  // ..........................................................
  // INTERNAL METHODS/PRIMITIVES
  //

  /**
    Load fixtures for a given fetchKey into the store
    and push it to the ret array.

    @param {SC.Store} store the store to load into
    @param {SC.Record} recordType the record type to load
    @param {SC.Array} ret is passed, array to add loaded storeKeys to.
    @returns {SC.Fixture} receiver
  */
  loadFixturesFor: function(store, recordType, ret) {
    var hashes   = [],
        dataHashes, i, storeKey ;

    dataHashes = this.fixturesFor(recordType);

    for(i in dataHashes){
      storeKey = recordType.storeKeyFor(i);
      if (store.peekStatus(storeKey) === SC.Record.EMPTY) {
        hashes.push(dataHashes[i]);
      }
      if (ret) ret.push(storeKey);
    }

    // only load records that were not already loaded to avoid infinite loops
    if (hashes && hashes.length>0) store.loadRecords(recordType, hashes);

    return this ;
  },

  /**
    Generates an id for the passed record type.  You can override this if
    needed.  The default generates a storekey and formats it as a string.

    @param {Class} recordType Subclass of SC.Record
    @param {Hash} dataHash the data hash for the record
    @param {SC.Store} store the store
    @param {Number} storeKey store key for the item
    @returns {String}
  */
  generateIdFor: function(recordType, dataHash, store, storeKey) {
    return "@id%@".fmt(SC.Store.generateStoreKey());
  },

  /**
    Based on the storeKey it returns the specified fixtures

    @param {SC.Store} store the store
    @param {Number} storeKey the storeKey
    @returns {Hash} data hash or null
  */
  fixtureForStoreKey: function(store, storeKey) {
    var id         = store.idFor(storeKey),
        recordType = store.recordTypeFor(storeKey),
        fixtures   = this.fixturesFor(recordType);
    return fixtures ? fixtures[id] : null;
  },

  /**
    Update the data hash fixture for the named store key.

    @param {SC.Store} store the store
    @param {Number} storeKey the storeKey
    @param {Hash} dataHash
    @returns {SC.FixturesDataSource} receiver
  */
  setFixtureForStoreKey: function(store, storeKey, dataHash) {
    var id         = store.idFor(storeKey),
        recordType = store.recordTypeFor(storeKey),
        fixtures   = this.fixturesFor(recordType);
    this._invalidateCachesFor(recordType, storeKey, id);
    fixtures[id] = dataHash;
    return this ;
  },

  /**
    Get the fixtures for the passed record type and prepare them if needed.
    Return cached value when complete.

    @param {SC.Record} recordType
    @returns {Hash} data hashes
  */
  fixturesFor: function(recordType) {
    // get basic fixtures hash.
    if (!this._fixtures) this._fixtures = {};
    var fixtures = this._fixtures[SC.guidFor(recordType)];
    if (fixtures) return fixtures ;

    // need to load fixtures.
    var dataHashes = recordType ? recordType.FIXTURES : null,
        len        = dataHashes ? dataHashes.length : 0,
        primaryKey = recordType ? recordType.prototype.primaryKey : 'guid',
        idx, dataHash, id ;

    this._fixtures[SC.guidFor(recordType)] = fixtures = {} ;
    for(idx=0;idx<len;idx++) {
      dataHash = dataHashes[idx];
      id = dataHash[primaryKey];
      if (!id) id = this.generateIdFor(recordType, dataHash);
      fixtures[id] = dataHash;
    }
    return fixtures;
  },

  /**
    Returns YES if fixtures for a given recordType have already been loaded

    @param {SC.Record} recordType
    @returns {Boolean} storeKeys
  */
  fixturesLoadedFor: function(recordType) {
    if (!this._fixtures) return NO;
    var ret = [], fixtures = this._fixtures[SC.guidFor(recordType)];
    return fixtures ? YES: NO;
  },

  /**
    Returns YES or SC.MIXED_STATE if one or more of the storeKeys can be
    handled by the fixture data source.

    @param {Array} storeKeys the store keys
    @returns {Boolean} YES if all handled, MIXED_STATE if some handled
  */
  hasFixturesFor: function(storeKeys) {
    var ret = NO ;
    storeKeys.forEach(function(storeKey) {
      if (ret !== SC.MIXED_STATE) {
        var recordType = SC.Store.recordTypeFor(storeKey),
            fixtures   = recordType ? recordType.FIXTURES : null ;
        if (fixtures && fixtures.length && fixtures.length>0) {
          if (ret === NO) ret = YES ;
        } else if (ret === YES) ret = SC.MIXED_STATE ;
      }
    }, this);

    return ret ;
  },

  /** @private
    Invalidates any internal caches based on the recordType and optional
    other parameters.  Currently this only invalidates the storeKeyCache used
    for fetch, but it could invalidate others later as well.

    @param {SC.Record} recordType the type of record modified
    @param {Number} storeKey optional store key
    @param {String} id optional record id
    @returns {SC.FixturesDataSource} receiver
  */
  _invalidateCachesFor: function(recordType, storeKey, id) {
    var cache = this._storeKeyCache;
    if (cache) delete cache[SC.guidFor(recordType)];
    return this ;
  }

});

/**
  Default fixtures instance for use in applications.

  @property {SC.FixturesDataSource}
*/
SC.Record.fixtures = SC.FixturesDataSource.create();
<|endoftext|>


<commit_before>const { createRemoteFileNode } = require(`gatsby-source-filesystem`)
const WebSocket = require("ws")
const { ApolloClient } = require("apollo-client")
const { InMemoryCache } = require("apollo-cache-inmemory")
const { split } = require("apollo-link")
const { HttpLink } = require("apollo-link-http")
const { WebSocketLink } = require("apollo-link-ws")
const { getMainDefinition } = require("apollo-utilities")
const fetch = require("node-fetch")
const gql = require("graphql-tag")

/**
 * ============================================================================
 * Create a GraphQL client to subscribe to live data changes
 * ============================================================================
 */

// Create an http link:
const httpLink = new HttpLink({
  uri: "http://localhost:4000",
  fetch,
})

// Create a WebSocket link:
const wsLink = new WebSocketLink({
  uri: `ws://localhost:4000`,
  options: {
    reconnect: true,
  },
  webSocketImpl: WebSocket,
})

// using the ability to split links, you can send data to each link/url
// depending on what kind of operation is being sent
const link = split(
  // split based on operation type
  ({ query }) => {
    const definition = getMainDefinition(query)
    return (
      definition.kind === "OperationDefinition" &&
      definition.operation === "subscription"
    )
  },
  wsLink,
  httpLink
)

const client = new ApolloClient({
  link,
  cache: new InMemoryCache(),
})

/**
 * ============================================================================
 * Helper functions and constants
 * ============================================================================
 */

const POST_NODE_TYPE = `Post`
const AUTHOR_NODE_TYPE = `Author`

// helper function for creating nodes
const createNodeFromData = (item, nodeType, helpers) => {
  const nodeMetadata = {
    id: helpers.createNodeId(`${nodeType}-${item.id}`),
    parent: null, // this is used if nodes are derived from other nodes, a little different than a foreign key relationship, more fitting for a transformer plugin that is changing the node
    children: [],
    internal: {
      type: nodeType,
      content: JSON.stringify(item),
      contentDigest: helpers.createContentDigest(item),
    },
  }

  const node = Object.assign({}, item, nodeMetadata)
  helpers.createNode(node)
  return node
}

/**
 * ============================================================================
 * Verify plugin loads
 * ============================================================================
 */

// should see message in console when running `gatsby develop` in example-site
exports.onPreInit = () => console.log("Loaded source-plugin")

/**
 * ============================================================================
 * Link nodes together with a customized GraphQL Schema
 * ============================================================================
 */

exports.createSchemaCustomization = ({ actions }) => {
  const { createTypes } = actions
  createTypes(`
    type Post implements Node {
      id: ID!
      slug: String!
      description: String!
      imgUrl: String!
      imgAlt: String!
      # create relationships between Post and File nodes for optimized images
      remoteImage: File @link
      # create relationships between Post and Author nodes
      author: Author @link(from: "author.name" by: "name")
    }

    type Author implements Node {
      id: ID!
      name: String!
    }`)
}

/**
 * ============================================================================
 * Source and cache nodes from the API
 * ============================================================================
 */

exports.sourceNodes = async function sourceNodes(
  {
    actions,
    cache,
    createContentDigest,
    createNodeId,
    getNodesByType,
    getNode,
  },
  pluginOptions
) {
  const { createNode, touchNode, deleteNode } = actions
  const helpers = Object.assign({}, actions, {
    createContentDigest,
    createNodeId,
  })

  // you can access plugin options here if need be
  console.log(`Space ID: ${pluginOptions.spaceId}`)

  // simple caching example, you can find in .cache/caches/source-plugin/some-diskstore
  await cache.set(`hello`, `world`)
  console.log(await cache.get(`hello`))

  // touch nodes to ensure they aren't garbage collected
  getNodesByType(POST_NODE_TYPE).forEach(node => touchNode(node)
  getNodesByType(AUTHOR_NODE_TYPE).forEach(node =>
    touchNode(node)
  )

  // listen for updates using subscriptions from the API
  if (pluginOptions.preview) {
    console.log(
      "Subscribing to updates on ws://localhost:4000 (plugin is in Preview mode)"
    )
    const subscription = await client.subscribe({
      query: gql`
        subscription {
          posts {
            id
            slug
            description
            imgUrl
            imgAlt
            author {
              id
              name
            }
            status
          }
        }
      `,
    })
    subscription.subscribe(({ data }) => {
      console.log(`Subscription received:`)
      console.log(data.posts)
      data.posts.forEach(post => {
        const nodeId = createNodeId(`${POST_NODE_TYPE}-${post.id}`)
        switch (post.status) {
          case "deleted":
            deleteNode(getNode(nodeId))
            break
          case "created":
          case "updated":
          default:
            // created and updated can be handled by the same code path
            // the post's id is presumed to stay constant (or can be inferred)
            createNodeFromData(post, POST_NODE_TYPE, helpers)
            break
        }
      })
    })
  }

  // store the response from the API in the cache
  const cacheKey = "your-source-data-key"
  let sourceData = await cache.get(cacheKey)

  // fetch fresh data if nothiing is found in the cache or a plugin option says not to cache data
  if (!sourceData || !pluginOptions.cacheResponse) {
    console.log("Not using cache for source data, fetching fresh content")
    const { data } = await client.query({
      query: gql`
        query {
          posts {
            id
            slug
            description
            imgUrl
            imgAlt
            author {
              id
              name
            }
          }
          authors {
            id
            name
          }
        }
      `,
    })
    await cache.set(cacheKey, data)
    sourceData = data
  }

  // loop through data returned from the api and create Gatsby nodes for them
  sourceData.posts.forEach(post =>
    createNodeFromData(post, POST_NODE_TYPE, helpers)
  )
  sourceData.authors.forEach(author =>
    createNodeFromData(author, AUTHOR_NODE_TYPE, helpers)
  )

  return
}

/**
 * ============================================================================
 * Transform remote file nodes
 * ============================================================================
 */

exports.onCreateNode = async ({
  actions: { createNode },
  getCache,
  createNodeId,
  node,
}) => {
  // transform remote file nodes using Gatsby sharp plugins
  // because onCreateNode is called for all nodes, verify that you are only running this code on nodes created by your plugin
  if (node.internal.type === POST_NODE_TYPE) {
    // create a FileNode in Gatsby that gatsby-transformer-sharp will create optimized images for
    const fileNode = await createRemoteFileNode({
      // the url of the remote image to generate a node for
      url: node.imgUrl,
      getCache,
      createNode,
      createNodeId,
      parentNodeId: node.id,
    })

    if (fileNode) {
      // used to add a field `remoteImage` to the Post node from the File node in the schemaCustomization API
      node.remoteImage = fileNode.id

      // inference can link these without schemaCustomization like this, but creates a less sturdy schema
      // node.remoteImage___NODE = fileNode.id
    }
  }
}
<commit_msg>Fixed syntax error in example (#31636)<commit_after>const { createRemoteFileNode } = require(`gatsby-source-filesystem`)
const WebSocket = require("ws")
const { ApolloClient } = require("apollo-client")
const { InMemoryCache } = require("apollo-cache-inmemory")
const { split } = require("apollo-link")
const { HttpLink } = require("apollo-link-http")
const { WebSocketLink } = require("apollo-link-ws")
const { getMainDefinition } = require("apollo-utilities")
const fetch = require("node-fetch")
const gql = require("graphql-tag")

/**
 * ============================================================================
 * Create a GraphQL client to subscribe to live data changes
 * ============================================================================
 */

// Create an http link:
const httpLink = new HttpLink({
  uri: "http://localhost:4000",
  fetch,
})

// Create a WebSocket link:
const wsLink = new WebSocketLink({
  uri: `ws://localhost:4000`,
  options: {
    reconnect: true,
  },
  webSocketImpl: WebSocket,
})

// using the ability to split links, you can send data to each link/url
// depending on what kind of operation is being sent
const link = split(
  // split based on operation type
  ({ query }) => {
    const definition = getMainDefinition(query)
    return (
      definition.kind === "OperationDefinition" &&
      definition.operation === "subscription"
    )
  },
  wsLink,
  httpLink
)

const client = new ApolloClient({
  link,
  cache: new InMemoryCache(),
})

/**
 * ============================================================================
 * Helper functions and constants
 * ============================================================================
 */

const POST_NODE_TYPE = `Post`
const AUTHOR_NODE_TYPE = `Author`

// helper function for creating nodes
const createNodeFromData = (item, nodeType, helpers) => {
  const nodeMetadata = {
    id: helpers.createNodeId(`${nodeType}-${item.id}`),
    parent: null, // this is used if nodes are derived from other nodes, a little different than a foreign key relationship, more fitting for a transformer plugin that is changing the node
    children: [],
    internal: {
      type: nodeType,
      content: JSON.stringify(item),
      contentDigest: helpers.createContentDigest(item),
    },
  }

  const node = Object.assign({}, item, nodeMetadata)
  helpers.createNode(node)
  return node
}

/**
 * ============================================================================
 * Verify plugin loads
 * ============================================================================
 */

// should see message in console when running `gatsby develop` in example-site
exports.onPreInit = () => console.log("Loaded source-plugin")

/**
 * ============================================================================
 * Link nodes together with a customized GraphQL Schema
 * ============================================================================
 */

exports.createSchemaCustomization = ({ actions }) => {
  const { createTypes } = actions
  createTypes(`
    type Post implements Node {
      id: ID!
      slug: String!
      description: String!
      imgUrl: String!
      imgAlt: String!
      # create relationships between Post and File nodes for optimized images
      remoteImage: File @link
      # create relationships between Post and Author nodes
      author: Author @link(from: "author.name" by: "name")
    }

    type Author implements Node {
      id: ID!
      name: String!
    }`)
}

/**
 * ============================================================================
 * Source and cache nodes from the API
 * ============================================================================
 */

exports.sourceNodes = async function sourceNodes(
  {
    actions,
    cache,
    createContentDigest,
    createNodeId,
    getNodesByType,
    getNode,
  },
  pluginOptions
) {
  const { createNode, touchNode, deleteNode } = actions
  const helpers = Object.assign({}, actions, {
    createContentDigest,
    createNodeId,
  })

  // you can access plugin options here if need be
  console.log(`Space ID: ${pluginOptions.spaceId}`)

  // simple caching example, you can find in .cache/caches/source-plugin/some-diskstore
  await cache.set(`hello`, `world`)
  console.log(await cache.get(`hello`))

  // touch nodes to ensure they aren't garbage collected
  getNodesByType(POST_NODE_TYPE).forEach(node => touchNode(node))
  getNodesByType(AUTHOR_NODE_TYPE).forEach(node =>
    touchNode(node)
  )

  // listen for updates using subscriptions from the API
  if (pluginOptions.preview) {
    console.log(
      "Subscribing to updates on ws://localhost:4000 (plugin is in Preview mode)"
    )
    const subscription = await client.subscribe({
      query: gql`
        subscription {
          posts {
            id
            slug
            description
            imgUrl
            imgAlt
            author {
              id
              name
            }
            status
          }
        }
      `,
    })
    subscription.subscribe(({ data }) => {
      console.log(`Subscription received:`)
      console.log(data.posts)
      data.posts.forEach(post => {
        const nodeId = createNodeId(`${POST_NODE_TYPE}-${post.id}`)
        switch (post.status) {
          case "deleted":
            deleteNode(getNode(nodeId))
            break
          case "created":
          case "updated":
          default:
            // created and updated can be handled by the same code path
            // the post's id is presumed to stay constant (or can be inferred)
            createNodeFromData(post, POST_NODE_TYPE, helpers)
            break
        }
      })
    })
  }

  // store the response from the API in the cache
  const cacheKey = "your-source-data-key"
  let sourceData = await cache.get(cacheKey)

  // fetch fresh data if nothiing is found in the cache or a plugin option says not to cache data
  if (!sourceData || !pluginOptions.cacheResponse) {
    console.log("Not using cache for source data, fetching fresh content")
    const { data } = await client.query({
      query: gql`
        query {
          posts {
            id
            slug
            description
            imgUrl
            imgAlt
            author {
              id
              name
            }
          }
          authors {
            id
            name
          }
        }
      `,
    })
    await cache.set(cacheKey, data)
    sourceData = data
  }

  // loop through data returned from the api and create Gatsby nodes for them
  sourceData.posts.forEach(post =>
    createNodeFromData(post, POST_NODE_TYPE, helpers)
  )
  sourceData.authors.forEach(author =>
    createNodeFromData(author, AUTHOR_NODE_TYPE, helpers)
  )

  return
}

/**
 * ============================================================================
 * Transform remote file nodes
 * ============================================================================
 */

exports.onCreateNode = async ({
  actions: { createNode },
  getCache,
  createNodeId,
  node,
}) => {
  // transform remote file nodes using Gatsby sharp plugins
  // because onCreateNode is called for all nodes, verify that you are only running this code on nodes created by your plugin
  if (node.internal.type === POST_NODE_TYPE) {
    // create a FileNode in Gatsby that gatsby-transformer-sharp will create optimized images for
    const fileNode = await createRemoteFileNode({
      // the url of the remote image to generate a node for
      url: node.imgUrl,
      getCache,
      createNode,
      createNodeId,
      parentNodeId: node.id,
    })

    if (fileNode) {
      // used to add a field `remoteImage` to the Post node from the File node in the schemaCustomization API
      node.remoteImage = fileNode.id

      // inference can link these without schemaCustomization like this, but creates a less sturdy schema
      // node.remoteImage___NODE = fileNode.id
    }
  }
}
<|endoftext|>


<commit_before>'use strict';

/* global CloudCmd, DOM, $ */

const itype = require('itype/legacy');
const rendy = require('rendy');
const exec = require('execon');

const {time} = require('../../common/util');
const {FS} = require('../../common/cloudfunc');

const Files = require('../dom/files');
const Events = require('../dom/events');
const load = require('../dom/load');
const Images = require('../dom/images');

CloudCmd.View = ViewProto;

module.exports = exec.bind();

module.exports.show = show;
module.exports.hide = hide;

let Loading = false;

const Name = 'View';
const Info = DOM.CurrentInfo;
const Key = CloudCmd.Key;
const basename = (a) => a.split('/').pop();

let El, TemplateAudio, Overlay;

const Config = {
    beforeShow: (callback) => {
        Images.hide();
        Key.unsetBind();
        showOverlay();
        exec(callback);
    },
    beforeClose: (callback) => {
        Events.rmKey(listener);
        Key.setBind();
        exec(callback);
        hideOverlay();
    },
    afterShow: (callback) => {
        El.focus();
        exec(callback);
    },
    afterClose      : exec,
    fitToView       : true,
    loop            : false,
    openEffect      : 'none',
    closeEffect     : 'none',
    autoSize        : false,
    height          : '100%',
    width           : '100%',
    minWidth        : 0,
    minHeight       : 0,
    padding         : 0,
    preload         : 0,
    keys            : null,
    mouseWheel      : false,
    arrows          : false,
    helpers         : {
        overlay : null,
        title   : null
    }
};

function ViewProto(callback) {
    const func = callback || exec.with(show, null);

    Loading = true;

    exec.series([
        DOM.loadJquery,
        loadAll,
        (callback) => {
            Loading = false;
            exec(callback);
        }
    ], func);

    Config.parent = Overlay = load({
        id          : 'js-view',
        name        : 'div',
        className   : 'fancybox-overlay fancybox-overlay-fixed'
    });

    ['click', 'contextmenu'].forEach((name) => {
        Events.add(name, Overlay, onOverLayClick);
    });

    return module.exports;
}

function show(data, options) {
    const prefixUrl = CloudCmd.PREFIX_URL + FS;

    if (Loading)
        return;

    if (options && options.bindKeys !== false)
        Events.addKey(listener);

    El = $('
');

    if (data) {
        const element = $(El).append(data);
        $.fancybox(element, initConfig(Config, options));
        return;
    }

    Images.show.load();

    const path = prefixUrl + Info.path;
    const type = getType(path);

    switch(type) {
    default:
        return Info.getData((error, data) => {
            if (error)
                return Images.hide();

            const element = document.createTextNode(data);
            /* add margin only for view text documents */
            El.css('margin', '2%');

            $.fancybox(El.append(element), Config);
        });

    case 'image':
        return showImage(path, prefixUrl);

    case 'media':
        return getMediaElement(path, (element) => {
            const media = DOM.getByDataName('js-media', element);
            const onKey = exec.with(onMediaKey, media);

            $.fancybox.open(element, {
                parent      : Overlay,
                beforeShow  : () => {
                    Config.beforeShow();
                    Events.addKey(onKey);
                },
                beforeClose : () => {
                    Config.beforeClose();
                    Events.rmKey(onKey);
                },
                afterShow: () => {
                    element
                        .querySelector('audio, video')
                        .focus();
                },
                helpers: {
                    overlay : null,
                    title   : null
                }
            });
        });
    }
}

function initConfig(Config, options) {
    const config = Object.assign({}, Config);

    if (!options)
        return config;

    Object.keys(options).forEach((name) => {
        const isConfig = !!config[name];
        const item = options[name];
        const isFunc = itype.function(item);

        if (!isFunc || !isConfig) {
            config[name] = options[name];
            return;
        }

        const func = config[name];
        config[name] = () => {
            exec.series([func, item]);
        };
    });

    return config;
}

function hide() {
    $.fancybox.close();
}

function showImage(href, prefixUrl) {
    const title = Info.name;
    const excludeCurrent = (path) => {
        return path !== Info.path;
    };

    const makeTitle = (path) => {
        return {
            href: prefixUrl + path,
            title: basename(path),
        };
    };

    const first = {
        href,
        title,
    };

    const names = Info.files
        .map(DOM.getCurrentPath)
        .filter(isImage)
        .filter(excludeCurrent)
        .map(makeTitle);

    const config = Object.assign({}, Config, {
        autoSize    : true,
        type        : 'image',
        prevEffect  : 'none',
        nextEffect  : 'none',
        arrows      : true,
        keys        : true,
        helpers     : {
            overlay : null,
            title   : {}
        }
    });

    const allNames = [first].concat(names);

    $.fancybox.open(allNames, config);
}

function isImage(name) {
    const images = [
        'jp(e|g|eg)',
        'gif',
        'png',
        'bmp',
        'webp',
        'svg',
        'ico'
    ];

    return images
        .map((ext) => RegExp(`\\.${ext}$`, 'i'))
        .some((reg) => reg.test(name));
}

function isMedia(name) {
    return isAudio(name) || isVideo(name);
}

function isAudio(name) {
    return /\.(mp3|ogg|m4a)$/i.test(name);
}

function isVideo(name) {
    return /\.(mp4|avi)$/i.test(name);
}

function getType(name) {
    if (isImage(name))
        return 'image';

    if (isMedia(name))
        return 'media';
}

function getMediaElement(src, callback) {
    check(src, callback);

    Files.get('view/media-tmpl', (error, template) => {
        const {name} = Info;

        if (error)
            return alert(error);

        if (!TemplateAudio)
            TemplateAudio   = template;

        const is = isAudio(name);
        const type =  is ? 'audio' : 'video';

        const rendered = rendy(TemplateAudio, {
            src,
            type,
            name,
        });

        const [element] = $(rendered);
        callback(element);
    });
}

function check(src, callback) {
    if (typeof src !== 'string')
        throw Error('src should be a string!');

    if (typeof callback !== 'function')
        throw Error('callback should be a function');
}

function onMediaKey(media, event) {
    const {keyCode} = event;

    if (keyCode === Key.SPACE) {
        if (media.paused)
            media.play();
        else
            media.pause();
    }
}

/**
 * function loads css and js of FancyBox
 * @callback   -  executes, when everything loaded
 */
function loadAll(callback) {
    time(Name + ' load');

    DOM.loadRemote('fancybox', () => {
        const {PREFIX} = CloudCmd;

        load.css(PREFIX + '/css/view.css', callback);

        load.style({
            id      : 'view-inlince-css',
            inner   : [
                '.fancybox-title-float-wrap .child {',
                '-webkit-border-radius: 0;',
                '-moz-border-radius: 0;',
                'border-radius: 0;',
                '}'
            ].join('')
        });
    });
}

function onOverLayClick(event) {
    const files = Info.files;
    const filesPassive = Info.filesPassive;
    const {target} = event;
    const isOverlay = target === Overlay;
    const position = {
        x: event.clientX,
        y: event.clientY
    };

    if (!isOverlay)
        return;

    hideOverlay();

    const element = DOM.getCurrentByPosition(position);

    if (!element)
        return;

    const isFiles = ~files.indexOf(element);
    const isFilesPassive = ~filesPassive.indexOf(element);

    if (!isFiles && !isFilesPassive)
        return;

    const isCurrent = DOM.isCurrentFile(element);

    if (isCurrent)
        return;

    DOM.setCurrentFile(element);

    hide();
}

function hideOverlay() {
    Overlay.classList.remove('view-overlay');
}

function showOverlay() {
    Overlay.classList.add('view-overlay');
}

function listener({keyCode}) {
    if (keyCode === Key.ESC)
        hide();
}

<commit_msg>fix(view) show: close view on ESC<commit_after>'use strict';

/* global CloudCmd, DOM, $ */

const itype = require('itype/legacy');
const rendy = require('rendy');
const exec = require('execon');

const {time} = require('../../common/util');
const {FS} = require('../../common/cloudfunc');

const Files = require('../dom/files');
const Events = require('../dom/events');
const load = require('../dom/load');
const Images = require('../dom/images');

CloudCmd.View = ViewProto;

module.exports = exec.bind();

module.exports.show = show;
module.exports.hide = hide;

let Loading = false;

const Name = 'View';
const Info = DOM.CurrentInfo;
const Key = CloudCmd.Key;
const basename = (a) => a.split('/').pop();

let El, TemplateAudio, Overlay;

const Config = {
    beforeShow: (callback) => {
        Images.hide();
        Key.unsetBind();
        showOverlay();
        exec(callback);
    },
    beforeClose: (callback) => {
        Events.rmKey(listener);
        Key.setBind();
        exec(callback);
        hideOverlay();
    },
    afterShow: (callback) => {
        El.focus();
        exec(callback);
    },
    afterClose      : exec,
    fitToView       : true,
    loop            : false,
    openEffect      : 'none',
    closeEffect     : 'none',
    autoSize        : false,
    height          : '100%',
    width           : '100%',
    minWidth        : 0,
    minHeight       : 0,
    padding         : 0,
    preload         : 0,
    keys            : null,
    mouseWheel      : false,
    arrows          : false,
    helpers         : {
        overlay : null,
        title   : null
    }
};

function ViewProto(callback) {
    const func = callback || exec.with(show, null);

    Loading = true;

    exec.series([
        DOM.loadJquery,
        loadAll,
        (callback) => {
            Loading = false;
            exec(callback);
        }
    ], func);

    Config.parent = Overlay = load({
        id          : 'js-view',
        name        : 'div',
        className   : 'fancybox-overlay fancybox-overlay-fixed'
    });

    ['click', 'contextmenu'].forEach((name) => {
        Events.add(name, Overlay, onOverLayClick);
    });

    return module.exports;
}

function show(data, options) {
    const prefixUrl = CloudCmd.PREFIX_URL + FS;

    if (Loading)
        return;

    if (!options || options.bindKeys !== false)
        Events.addKey(listener);

    El = $('
');

    if (data) {
        const element = $(El).append(data);
        $.fancybox(element, initConfig(Config, options));
        return;
    }

    Images.show.load();

    const path = prefixUrl + Info.path;
    const type = getType(path);

    switch(type) {
    default:
        return Info.getData((error, data) => {
            if (error)
                return Images.hide();

            const element = document.createTextNode(data);
            /* add margin only for view text documents */
            El.css('margin', '2%');

            $.fancybox(El.append(element), Config);
        });

    case 'image':
        return showImage(path, prefixUrl);

    case 'media':
        return getMediaElement(path, (element) => {
            const media = DOM.getByDataName('js-media', element);
            const onKey = exec.with(onMediaKey, media);

            $.fancybox.open(element, {
                parent      : Overlay,
                beforeShow  : () => {
                    Config.beforeShow();
                    Events.addKey(onKey);
                },
                beforeClose : () => {
                    Config.beforeClose();
                    Events.rmKey(onKey);
                },
                afterShow: () => {
                    element
                        .querySelector('audio, video')
                        .focus();
                },
                helpers: {
                    overlay : null,
                    title   : null
                }
            });
        });
    }
}

function initConfig(Config, options) {
    const config = Object.assign({}, Config);

    if (!options)
        return config;

    Object.keys(options).forEach((name) => {
        const isConfig = !!config[name];
        const item = options[name];
        const isFunc = itype.function(item);

        if (!isFunc || !isConfig) {
            config[name] = options[name];
            return;
        }

        const func = config[name];
        config[name] = () => {
            exec.series([func, item]);
        };
    });

    return config;
}

function hide() {
    $.fancybox.close();
}

function showImage(href, prefixUrl) {
    const title = Info.name;
    const excludeCurrent = (path) => {
        return path !== Info.path;
    };

    const makeTitle = (path) => {
        return {
            href: prefixUrl + path,
            title: basename(path),
        };
    };

    const first = {
        href,
        title,
    };

    const names = Info.files
        .map(DOM.getCurrentPath)
        .filter(isImage)
        .filter(excludeCurrent)
        .map(makeTitle);

    const config = Object.assign({}, Config, {
        autoSize    : true,
        type        : 'image',
        prevEffect  : 'none',
        nextEffect  : 'none',
        arrows      : true,
        keys        : true,
        helpers     : {
            overlay : null,
            title   : {}
        }
    });

    const allNames = [first].concat(names);

    $.fancybox.open(allNames, config);
}

function isImage(name) {
    const images = [
        'jp(e|g|eg)',
        'gif',
        'png',
        'bmp',
        'webp',
        'svg',
        'ico'
    ];

    return images
        .map((ext) => RegExp(`\\.${ext}$`, 'i'))
        .some((reg) => reg.test(name));
}

function isMedia(name) {
    return isAudio(name) || isVideo(name);
}

function isAudio(name) {
    return /\.(mp3|ogg|m4a)$/i.test(name);
}

function isVideo(name) {
    return /\.(mp4|avi)$/i.test(name);
}

function getType(name) {
    if (isImage(name))
        return 'image';

    if (isMedia(name))
        return 'media';
}

function getMediaElement(src, callback) {
    check(src, callback);

    Files.get('view/media-tmpl', (error, template) => {
        const {name} = Info;

        if (error)
            return alert(error);

        if (!TemplateAudio)
            TemplateAudio   = template;

        const is = isAudio(name);
        const type =  is ? 'audio' : 'video';

        const rendered = rendy(TemplateAudio, {
            src,
            type,
            name,
        });

        const [element] = $(rendered);
        callback(element);
    });
}

function check(src, callback) {
    if (typeof src !== 'string')
        throw Error('src should be a string!');

    if (typeof callback !== 'function')
        throw Error('callback should be a function');
}

function onMediaKey(media, event) {
    const {keyCode} = event;

    if (keyCode === Key.SPACE) {
        if (media.paused)
            media.play();
        else
            media.pause();
    }
}

/**
 * function loads css and js of FancyBox
 * @callback   -  executes, when everything loaded
 */
function loadAll(callback) {
    time(Name + ' load');

    DOM.loadRemote('fancybox', () => {
        const {PREFIX} = CloudCmd;

        load.css(PREFIX + '/css/view.css', callback);

        load.style({
            id      : 'view-inlince-css',
            inner   : [
                '.fancybox-title-float-wrap .child {',
                '-webkit-border-radius: 0;',
                '-moz-border-radius: 0;',
                'border-radius: 0;',
                '}'
            ].join('')
        });
    });
}

function onOverLayClick(event) {
    const files = Info.files;
    const filesPassive = Info.filesPassive;
    const {target} = event;
    const isOverlay = target === Overlay;
    const position = {
        x: event.clientX,
        y: event.clientY
    };

    if (!isOverlay)
        return;

    hideOverlay();

    const element = DOM.getCurrentByPosition(position);

    if (!element)
        return;

    const isFiles = ~files.indexOf(element);
    const isFilesPassive = ~filesPassive.indexOf(element);

    if (!isFiles && !isFilesPassive)
        return;

    const isCurrent = DOM.isCurrentFile(element);

    if (isCurrent)
        return;

    DOM.setCurrentFile(element);

    hide();
}

function hideOverlay() {
    Overlay.classList.remove('view-overlay');
}

function showOverlay() {
    Overlay.classList.add('view-overlay');
}

function listener({keyCode}) {
    if (keyCode === Key.ESC)
        hide();
}

<|endoftext|>