<commit_before>/* @flow weak */

/**
 * OfflineMobile Android Index
 * Sustainable Solutions (NZ) Ltd. 2016
 */

import React from 'react';
import {
  StyleSheet,
  Text,
  View,
} from 'react-native';

import { Navigator } from './navigation';

import {
  CustomerInvoicePage,
  CustomerInvoicesPage,
  CustomerPage,
  CustomersPage,
  FirstUsePage,
  MenuPage,
  StockHistoriesPage,
  StockHistoryPage,
  StockPage,
  StocktakeEditPage,
  StocktakeManagePage,
  StocktakesPage,
  SupplierInvoicePage,
  SupplierInvoicesPage,
  RealmExplorer,
} from './pages';

import { LoginModal } from './widgets';

import { Synchronizer } from './sync';
import { SyncAuthenticator, UserAuthenticator } from './authentication';
import { Database, schema } from './database';
import { Scheduler } from './Scheduler';
import { Settings } from './settings';

const SYNC_INTERVAL = 10 * 60 * 1000; // 10 minutes in milliseconds
const AUTHENTICATION_INTERVAL = 10 * 60 * 1000; // 10 minutes in milliseconds
const SYNC_STATES = {
  WAITING: 'sync_waiting',
  SYNCING: 'sync_active',
  ERROR: 'sync_error',
};

export default class OfflineMobileApp extends React.Component {

  constructor() {
    super();
    this.database = new Database(schema);
    this.settings = new Settings(this.database);
    this.userAuthenticator = new UserAuthenticator(this.database, this.settings);
    const syncAuthenticator = new SyncAuthenticator(this.database, this.settings);
    this.synchronizer = new Synchronizer(this.database, syncAuthenticator, this.settings);
    this.scheduler = new Scheduler();
    const initialised = this.synchronizer.isInitialised();
    this.state = {
      initialised: initialised,
      authenticated: false,
      syncState: SYNC_STATES.WAITING,
      syncError: '',
    };
  }

  componentWillMount() {
    this.onAuthentication = this.onAuthentication.bind(this);
    this.onInitialised = this.onInitialised.bind(this);
    this.renderScene = this.renderScene.bind(this);
    this.renderSyncState = this.renderSyncState.bind(this);
    this.synchronize = this.synchronize.bind(this);
    this.scheduler.schedule(this.synchronize,
                            SYNC_INTERVAL);
    this.scheduler.schedule(() => this.userAuthenticator.reauthenticate(this.onAuthentication),
                            AUTHENTICATION_INTERVAL);
  }

  componentWillUnmount() {
    this.scheduler.clearAll();
  }

  onAuthentication(authenticated) {
    this.setState({ authenticated: authenticated });
  }

  onInitialised() {
    this.setState({ initialised: true });
  }

  async synchronize() {
    if (this.state.syncState === SYNC_STATES.SYNCING) return; // If already syncing, skip
    try {
      this.setState({ syncState: SYNC_STATES.SYNCING });
      await this.synchronizer.synchronize();
      this.setState({ syncState: SYNC_STATES.WAITING });
    } catch (error) {
      this.setState({
        syncState: SYNC_STATES.ERROR,
        syncError: error.message,
      });
    }
  }

  renderScene(props) {
    const navigateTo = (key, title) => {
      props.onNavigate({ type: 'push', key, title });
    };
    switch (props.scene.navigationState.key) {
      case 'menu':
        return <MenuPage navigateTo={navigateTo} />;
      case 'customers':
        return <CustomersPage database={this.database} navigateTo={navigateTo} />;
      case 'customer':
        return <CustomerPage navigateTo={navigateTo} />;
      case 'stock':
        return <StockPage database={this.database} navigateTo={navigateTo} />;
      case 'stocktakes':
        return <StocktakesPage database={this.database} navigateTo={navigateTo} />;
      case 'stocktakeEditor':
        return <StocktakeEditPage navigateTo={navigateTo} />;
      case 'stocktakeManager':
        return <StocktakeManagePage navigateTo={navigateTo} />;
      case 'customerInvoices':
        return <CustomerInvoicesPage database={this.database} navigateTo={navigateTo} />;
      case 'customerInvoice':
        return <CustomerInvoicePage navigateTo={navigateTo} />;
      case 'supplierInvoices':
        return <SupplierInvoicesPage database={this.database} navigateTo={navigateTo} />;
      case 'supplierInvoice':
        return <SupplierInvoicePage navigateTo={navigateTo} />;
      case 'stockHistories':
        return <StockHistoriesPage navigateTo={navigateTo} />;
      case 'stockHistory':
        return <StockHistoryPage navigateTo={navigateTo} />;
      case 'realmExplorer':
        return <RealmExplorer navigateTo={navigateTo} database={this.database} />;
      case 'root':
      default:
        return <MenuPage navigateTo={navigateTo} />;
    }
  }

  renderSyncState() {
    return (
      <Text>
        {this.state.syncState}
      </Text>
    );
  }

  render() {
    if (!this.state.initialised) {
      return (
        <FirstUsePage
          synchronizer={this.synchronizer}
          onInitialised={this.onInitialised}
        />
      );
    }
    return (
      <View style={styles.container}>
        <Navigator
          renderScene={this.renderScene}
          renderRightComponent={this.renderSyncState}
        />
        <LoginModal
          authenticator={this.userAuthenticator}
          isAuthenticated={this.state.authenticated}
          onAuthentication={this.onAuthentication}
        />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
});
<commit_msg>Show sync errors in nav bar<commit_after>/* @flow weak */

/**
 * OfflineMobile Android Index
 * Sustainable Solutions (NZ) Ltd. 2016
 */

import React from 'react';
import {
  StyleSheet,
  Text,
  View,
} from 'react-native';

import { Navigator } from './navigation';

import {
  CustomerInvoicePage,
  CustomerInvoicesPage,
  CustomerPage,
  CustomersPage,
  FirstUsePage,
  MenuPage,
  StockHistoriesPage,
  StockHistoryPage,
  StockPage,
  StocktakeEditPage,
  StocktakeManagePage,
  StocktakesPage,
  SupplierInvoicePage,
  SupplierInvoicesPage,
  RealmExplorer,
} from './pages';

import { LoginModal } from './widgets';

import { Synchronizer } from './sync';
import { SyncAuthenticator, UserAuthenticator } from './authentication';
import { Database, schema } from './database';
import { Scheduler } from './Scheduler';
import { Settings } from './settings';

const SYNC_INTERVAL = 10 * 60 * 1000; // 10 minutes in milliseconds
const AUTHENTICATION_INTERVAL = 10 * 60 * 1000; // 10 minutes in milliseconds
const SYNC_STATES = {
  WAITING: 'sync_waiting',
  SYNCING: 'sync_active',
  ERROR: 'sync_error',
};

export default class OfflineMobileApp extends React.Component {

  constructor() {
    super();
    this.database = new Database(schema);
    this.settings = new Settings(this.database);
    this.userAuthenticator = new UserAuthenticator(this.database, this.settings);
    const syncAuthenticator = new SyncAuthenticator(this.database, this.settings);
    this.synchronizer = new Synchronizer(this.database, syncAuthenticator, this.settings);
    this.scheduler = new Scheduler();
    const initialised = this.synchronizer.isInitialised();
    this.state = {
      initialised: initialised,
      authenticated: false,
      syncState: SYNC_STATES.WAITING,
      syncError: '',
    };
  }

  componentWillMount() {
    this.onAuthentication = this.onAuthentication.bind(this);
    this.onInitialised = this.onInitialised.bind(this);
    this.renderScene = this.renderScene.bind(this);
    this.renderSyncState = this.renderSyncState.bind(this);
    this.synchronize = this.synchronize.bind(this);
    this.scheduler.schedule(this.synchronize,
                            SYNC_INTERVAL);
    this.scheduler.schedule(() => this.userAuthenticator.reauthenticate(this.onAuthentication),
                            AUTHENTICATION_INTERVAL);
  }

  componentWillUnmount() {
    this.scheduler.clearAll();
  }

  onAuthentication(authenticated) {
    this.setState({ authenticated: authenticated });
  }

  onInitialised() {
    this.setState({ initialised: true });
  }

  async synchronize() {
    if (this.state.syncState === SYNC_STATES.SYNCING) return; // If already syncing, skip
    try {
      this.setState({ syncState: SYNC_STATES.SYNCING });
      await this.synchronizer.synchronize();
      this.setState({ syncState: SYNC_STATES.WAITING });
    } catch (error) {
      this.setState({
        syncState: SYNC_STATES.ERROR,
        syncError: error.message,
      });
    }
  }

  renderScene(props) {
    const navigateTo = (key, title) => {
      props.onNavigate({ type: 'push', key, title });
    };
    switch (props.scene.navigationState.key) {
      case 'menu':
        return <MenuPage navigateTo={navigateTo} />;
      case 'customers':
        return <CustomersPage database={this.database} navigateTo={navigateTo} />;
      case 'customer':
        return <CustomerPage navigateTo={navigateTo} />;
      case 'stock':
        return <StockPage database={this.database} navigateTo={navigateTo} />;
      case 'stocktakes':
        return <StocktakesPage database={this.database} navigateTo={navigateTo} />;
      case 'stocktakeEditor':
        return <StocktakeEditPage navigateTo={navigateTo} />;
      case 'stocktakeManager':
        return <StocktakeManagePage navigateTo={navigateTo} />;
      case 'customerInvoices':
        return <CustomerInvoicesPage database={this.database} navigateTo={navigateTo} />;
      case 'customerInvoice':
        return <CustomerInvoicePage navigateTo={navigateTo} />;
      case 'supplierInvoices':
        return <SupplierInvoicesPage database={this.database} navigateTo={navigateTo} />;
      case 'supplierInvoice':
        return <SupplierInvoicePage navigateTo={navigateTo} />;
      case 'stockHistories':
        return <StockHistoriesPage navigateTo={navigateTo} />;
      case 'stockHistory':
        return <StockHistoryPage navigateTo={navigateTo} />;
      case 'realmExplorer':
        return <RealmExplorer navigateTo={navigateTo} database={this.database} />;
      case 'root':
      default:
        return <MenuPage navigateTo={navigateTo} />;
    }
  }

  renderSyncState() {
    let syncText = this.state.syncState;
    if (syncText === SYNC_STATES.ERROR) syncText = this.state.syncError;
    return (
      <Text>
        {syncText}
      </Text>
    );
  }

  render() {
    if (!this.state.initialised) {
      return (
        <FirstUsePage
          synchronizer={this.synchronizer}
          onInitialised={this.onInitialised}
        />
      );
    }
    return (
      <View style={styles.container}>
        <Navigator
          renderScene={this.renderScene}
          renderRightComponent={this.renderSyncState}
        />
        <LoginModal
          authenticator={this.userAuthenticator}
          isAuthenticated={this.state.authenticated}
          onAuthentication={this.onAuthentication}
        />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
});
<|endoftext|>


<commit_before>

var	_ = require("underscore"),
	jwt = require("jsonwebtoken"),
	utils = require("./utils");

module.exports = function(options){

	if(!options.client || !options.secret)
		throw new Error("Redis client and secret required for jwtRedisSession!");

	var sessionMethods = utils({
		client: options.client,
		secret: options.secret,
		algorithm: options.algorithm || "HS256",
		keyspace: options.keyspace || "sess:",
		maxAge: options.maxAge || 86400000
	});

	return function(req, res, next){

		req.session = {};

		_.each(sessionMethods, function(fn, name){
			_.bind(fn, req.session);
		});

		console.log("req.session after methods ", req.session, typeof req.session.save);

		var token = (req.body && req.body.accessToken)
			|| (req.query && req.query.accessToken)
			|| req.get("x-access-token");

		if(token){
			jwt.verify(token, options.secret, function(error, decoded){
				if(error || !decoded.iss)
					return next();

				options.client.get(options.keyspace + decoded.iss, function(err, session){
					if(err || !session)
						return next();

					try{
						session = JSON.parse(session);
					}catch(e){
						return next();
					}

					_.extend(req.session, session);
					req.session.id = decoded.iss;
					console.log("req.session after getting redis data ", req.session);

					req.session.touch(); // update the TTL
					next();
				});
			});
		}else{
			next();
		}
	};

};
<commit_msg>changed extension for session<commit_after>

var	_ = require("underscore"),
	jwt = require("jsonwebtoken"),
	utils = require("./utils");

module.exports = function(options){

	if(!options.client || !options.secret)
		throw new Error("Redis client and secret required for jwtRedisSession!");

	var sessionMethods = utils({
		client: options.client,
		secret: options.secret,
		algorithm: options.algorithm || "HS256",
		keyspace: options.keyspace || "sess:",
		maxAge: options.maxAge || 86400000
	});

	return function(req, res, next){

		req.session = {};

		_.extend(req.session, sessionMethods);

		console.log("req.session after methods ", req.session, typeof req.session.save);

		var token = (req.body && req.body.accessToken)
			|| (req.query && req.query.accessToken)
			|| req.get("x-access-token");

		if(token){
			jwt.verify(token, options.secret, function(error, decoded){
				if(error || !decoded.iss)
					return next();

				options.client.get(options.keyspace + decoded.iss, function(err, session){
					if(err || !session)
						return next();

					try{
						session = JSON.parse(session);
					}catch(e){
						return next();
					}

					_.extend(req.session, session);
					req.session.id = decoded.iss;
					console.log("req.session after getting redis data ", req.session);

					req.session.touch(); // update the TTL
					next();
				});
			});
		}else{
			next();
		}
	};

};
<|endoftext|>


<commit_before>/*!
 * qwebs
 * Copyright(c) 2015 Benoît Claveau
 * MIT Licensed
 */

"use strict";

const request = require('request');
const DataError = require("./../dataerror");
const JSONStream = require("JSONStream");

class ClientService {
    constructor() {
    };

    parse(httpResponse) {
       if (httpResponse.header["Content-Type"].match(/\bapplication\/json\b/)) {
         if (httpResponse.body && !(httpResponse.body instanceof String)) {
            httpResponse.body = JSON.parse(httpResponse.body);
         }
       }
    };

    get(options) {
        return new Promise((resolve, reject) => {
            options = options || {};
            return request.get(options, (err, httpResponse, body) => {
                if (err) reject(err);
                else {
                 this.parse(httpResponse);
                 resolve(httpResponse);
                }
            });
        });
    };

    post(options) {
        return new Promise((resolve, reject) => {
            options = options || {};
            return request.post(options, (err, httpResponse, body) => {
                if (err) reject(err);
                else {
                 this.parse(httpResponse);
                 resolve(httpResponse);
                }
            });
        });
    };

    put(options) {
        return new Promise((resolve, reject) => {
            options = options || {};
            return request.put(options, (err, httpResponse, body) => {
                if (err) reject(err);
                else {
                 this.parse(httpResponse);
                 resolve(httpResponse);
                }
            });
        });
    };

    delete(options) {
        return new Promise((resolve, reject) => {
            options = options || {};
            return request.delete(options, (err, httpResponse, body) => {
                if (err) reject(err);
                else {
                 this.parse(httpResponse);
                 resolve(httpResponse);
                }
            });
        });
    };
};

exports = module.exports = ClientService;
<commit_msg>Update client.js<commit_after>/*!
 * qwebs
 * Copyright(c) 2015 Benoît Claveau
 * MIT Licensed
 */

"use strict";

const request = require('request');
const DataError = require("./../dataerror");
const JSONStream = require("JSONStream");

class ClientService {
    constructor() {
    };

    parse(httpResponse) {
       if (httpResponse.headers["Content-Type"].match(/\bapplication\/json\b/)) {
         if (httpResponse.body && !(httpResponse.body instanceof String)) {
            httpResponse.body = JSON.parse(httpResponse.body);
         }
       }
    };

    get(options) {
        return new Promise((resolve, reject) => {
            options = options || {};
            return request.get(options, (err, httpResponse, body) => {
                if (err) reject(err);
                else {
                 this.parse(httpResponse);
                 resolve(httpResponse);
                }
            });
        });
    };

    post(options) {
        return new Promise((resolve, reject) => {
            options = options || {};
            return request.post(options, (err, httpResponse, body) => {
                if (err) reject(err);
                else {
                 this.parse(httpResponse);
                 resolve(httpResponse);
                }
            });
        });
    };

    put(options) {
        return new Promise((resolve, reject) => {
            options = options || {};
            return request.put(options, (err, httpResponse, body) => {
                if (err) reject(err);
                else {
                 this.parse(httpResponse);
                 resolve(httpResponse);
                }
            });
        });
    };

    delete(options) {
        return new Promise((resolve, reject) => {
            options = options || {};
            return request.delete(options, (err, httpResponse, body) => {
                if (err) reject(err);
                else {
                 this.parse(httpResponse);
                 resolve(httpResponse);
                }
            });
        });
    };
};

exports = module.exports = ClientService;
<|endoftext|>


<commit_before>import XMLParser from './XMLParser.js';
import {log, absoluteURL, getClassFromName} from './Util.js';
import ModulePool from './ModulePool.js';
import ModelPool from './ModelPool.js';
import Router from './Router.js';
import Cacher from './Cacher.js';
import PageConfiguration from './PageConfiguration.js';
import Page from './Page.js';
import PageFactory from './PageFactory.js';
import GenericConfiguration from './GenericConfiguration.js';
import Route from './Route.js';
import ModuleConfiguration from './ModuleConfiguration.js';
import Context from './Context.js';
import PageBuilder from './PageBuilder.js';
import GenericConnector from './GenericConnector.js';
import AccessController from './AccessController.js';
import NotSupportedEngineError from './Errors/NotSupportedEngineError.js';
import Database from './Database.js';
import FrameworkException from './Exceptions/FrameworkException.js';
import Sandbox from 'js-sandbox';

export default class AppController{
	constructor(xmlConfiguration){
		this.moduleOnLoad = [];
		this.initialization = true;
		XMLParser.parseUrl(xmlConfiguration,this.processConf.bind(this));
	}
	registerModel(model){
		ModelPool.addModel(model);
	}
	registerModule(module){
		if(this.initialization)
			this.moduleOnLoad.push(module);
		else
			ModulePool.addModule(module);
	}
	registerRoute(route){
		Router.addRoute(route);
	}
	addToGlobalContext(name, obj){
		var globalContext = Context.getGlobal();
		if(name in globalContext)
			throw new FrameworkException('A module tried to edit global context!');
		else
			globalContext[name] = obj;
	}
	processConf(conf){
		if(!conf) return;
		var hold_conf = {};
		try{
			var temp_configuration = conf.getElementsByTagName('configuration')[0];
			hold_conf.container = (temp_configuration.getElementsByTagName('container')[0]).textContent;
			if((temp_configuration.getElementsByTagName('base_url')).length>0)
				hold_conf.base_url = (temp_configuration.getElementsByTagName('base_url')[0]).textContent;
			else{
				var path = document.location.pathname.split('/');
				path.pop();
				hold_conf.base_url = document.location.protocol + '//' + document.location.host + path.join('/');
			}
			var pageBuilder_conf = (temp_configuration.getElementsByTagName('pageBuilder')[0]);
			var cache_whitelist = [];
			var cache_blacklist = [];
			var cache_maxcached = 1000;
			var cacher_conf = (temp_configuration.getElementsByTagName('cacher')[0]);
			if(cacher_conf){
				if(cacher_conf.getAttribute('max-cached'))
					cache_maxcached = parseInt(cacher_conf.getAttribute('max-cached'));
				if(cacher_conf.getElementsByTagName('block'))
					for( var b of cacher_conf.getElementsByTagName('block')){
						cache_blacklist.push(b.getAttribute('url'));
					}
				if(cacher_conf.getElementsByTagName('persist'))
					for( var p of cacher_conf.getElementsByTagName('persist')){
						cache_whitelist.push(p.getAttribute('url'));
					}
			}
			var cacher_promise = Cacher.init(cache_maxcached, cache_whitelist, cache_blacklist);
			var page_container = temp_configuration.getElementsByTagName('pages')[0];
			var pages_index = page_container.getElementsByTagName('index')[0];
			var pages_path = page_container.getAttribute('path');
			var pages_transition = page_container.getAttribute('transition') || null;
			for( var p of page_container.getElementsByTagName('page')){
				var modulesAll = null;
				var rolesAllowed = null;
				if(p.getAttribute('modulesAllowed'))
					modulesAll = p.getAttribute('modulesAllowed').split(',');
				if(p.getAttribute('rolesAllowed'))
					rolesAllowed = p.getAttribute('rolesAllowed').split(',');
				var hold_vconf = {};
				if(p.getElementsByTagName('configuration') && p.getElementsByTagName('configuration').length > 0)
					for(var c of (p.getElementsByTagName('configuration')[0]).childNodes){
						if(c instanceof Element)
							hold_vconf[c.tagName] = c.textContent;
					}
				var confPage = new PageConfiguration(hold_vconf);
				var newPage = new Page(p.getAttribute('path'), //pages_path+
					parseInt(p.getAttribute('vid')),(p.getAttribute('noback')=='true'),confPage, modulesAll,
					(p.hasAttribute('keepLive')) ? (p.getAttribute('keepLive')=='true') : undefined,
					(p.hasAttribute('allowDuplicate')) ? (p.getAttribute('allowDuplicate')=='true') : undefined,
					(p.hasAttribute('ghostPage')) ? (p.getAttribute('ghostPage')=='true') : undefined, rolesAllowed);
				PageFactory.addPage(newPage);
			}
			AppController.configuration = new GenericConfiguration(hold_conf);
			var route_container = temp_configuration.getElementsByTagName('routes')[0];
			if(route_container){
				for( var r of route_container.getElementsByTagName('route')){
					this.registerRoute(new Route(r.getAttribute('entry'), r.getAttribute('destination')));
				}
			}
			var module_container = temp_configuration.getElementsByTagName('modules')[0];
			var current_promise = null;
			if(module_container){
				var modules_path = module_container.getAttribute('path');
				if(!modules_path.startsWith(hold_conf.base_url))
					modules_path = absoluteURL(hold_conf.base_url, modules_path, false);
				var moduleConfs = {};
				var hiddenIfr = document.createElement('iframe');
				hiddenIfr.style.display = 'none';
				document.body.appendChild(hiddenIfr);
				for(var v in window){
					if(!(v in hiddenIfr.contentWindow))
						hiddenIfr.contentWindow[v] = window[v];
				}
				hiddenIfr.contentWindow.Promise = window.Promise;
				hiddenIfr.contentWindow.Array = window.Array;
				hiddenIfr.contentWindow.Element = window.Element;
				hiddenIfr.contentWindow._document = new Proxy(document, {
					container: document.getElementById(hold_conf.container),
					whiteList: [
						'querySelector',
						'getElementById',
						'dispatchEvent',
						'createElement'
					],
					get: function(target, name) {
						var ret = ((typeof target[name] != 'function') || this.whiteList.indexOf(name)!=-1) ?
							target[name] :
							undefined;
						if(typeof ret == 'function' && name != 'createElement'){
							ret = function(next){
								var args = [];
								for(var i=1; i<arguments.length; i++)
									args[i-1] = arguments[i];
								var res = next.apply(document, args);
								if(res instanceof Node){
									var hold = res;
									while (hold = hold.parentNode)
										if (hold == this)
											return res;
									return this;
								}
							}.bind(this.container,ret);

						}
						return ret.bind(target);
					},
					set: function(obj, prop, value) {
						return false;
					}
				});
				for( var m of module_container.getElementsByTagName('module')){
					if(m.getAttribute('enabled') == 'true'){
						var hold_mconf = {};
						var modulePerm = m.getAttribute('permissions') ? m.getAttribute('permissions').split(',') : [];
						var xml2obj_func = function(ele){
							var hold_return = {};
							for(var c of ele.childNodes){
								if(c instanceof Element)
									if (c.hasChildNodes())
										hold_return[c.tagName] = xml2obj_func(c);
									else
										hold_return[c.tagName] = c.textContent;
							}
							return hold_return;
						};
						hold_mconf = xml2obj_func(m.getElementsByTagName('configuration')[0]);
						var confModule = new ModuleConfiguration(hold_mconf);
						current_promise = new Promise(
							function(confModule, modulePerm, current_promise, resolve, reject){
								var mod_load_func = function(confModule, modulePerm, resolve){
									var script = document.createElement("script");
									script.src = modules_path + m.getAttribute('path');
									script.type = 'module';
									script.onload = function(modules, configuration, permissions, callback){
										while(modules.length>0){
											var sm = modules.shift();
											moduleConfs[sm.name] = configuration;
											ModulePool.addModule(sm, permissions);
										}
										callback();
									}.bind(script, this.moduleOnLoad, confModule, modulePerm, resolve);
									if(modules_path.startsWith('file:')){
										var prefetchxhr = new XMLHttpRequest();
										prefetchxhr.onload = function(m, script, hiddenIfr, e){
											let blob = prefetchxhr.response;
											let newblob = new Blob([blob], {type: 'text/javascript'});
											script.src = URL.createObjectURL(newblob);
											hiddenIfr.contentDocument.head.appendChild(script);
										}.bind(this, m, script, hiddenIfr);
										prefetchxhr.open('get', modules_path + m.getAttribute('path'));
										prefetchxhr.responseType = 'blob';
										prefetchxhr.send();
									}else
										hiddenIfr.contentDocument.head.appendChild(script);
								}.bind(this, confModule, modulePerm, resolve);
								if(current_promise!=null)
									current_promise.then(mod_load_func);
								else
									mod_load_func();
							}.bind(this, confModule, modulePerm, current_promise)
						).catch(function(e) {
							log(e);
						});
					}
				}
			}
			var newBase = document.createElement("base");
			newBase.setAttribute("href", pages_path);
			document.getElementsByTagName("head")[0].appendChild(newBase);
			var newBaseIfr = hiddenIfr.contentDocument.createElement("base");
			newBaseIfr.setAttribute("href", hold_conf.base_url+'/'+pages_path);
			hiddenIfr.contentDocument.getElementsByTagName("head")[0].appendChild(newBaseIfr);
			Promise.all([cacher_promise, current_promise]).then(function(){
				var globalContext = Context.getGlobal();
				globalContext.BobbleHead = new Proxy(BobbleHead, {
					whiteList: [
						'User',
						'Role',
						'Session',
						'Response',
						'Request',
						'ConnectorRequest',
						'Model',
						'ModelInstance',
						'Route',
						'Page',
						'PageContext',
						'AuthenticationMethod',
						'AuthenticationMethods',
						'PageFactory',
						'VirtualPage',
						'Exceptions',
						'Errors',
						'Events',
						'Util'
					],
					get: function(target, name) {
						return (name in target && this.whiteList.indexOf(name)!=-1) ?
							target[name] :
							null;
					}
				});
				if(pageBuilder_conf){
					pageBuilder_conf = pageBuilder_conf.textContent;
					try{
						var pageBuildClass = getClassFromName(pageBuilder_conf) ||
							getClassFromName(pageBuilder_conf, hiddenIfr.contentWindow);
						if(!pageBuildClass)
							throw new FrameworkException(pageBuilder_conf + ' isn\'t a valid PageBuilder');
						globalContext.pageBuilder = pageBuilder_conf ?
							new (pageBuildClass)() :
							new PageBuilder();
					}catch(e){
						log(e);
						globalContext.pageBuilder = new PageBuilder();
					}
				}else
					globalContext.pageBuilder = new PageBuilder();
				globalContext.pageBuilder.container = hold_conf.container;
				globalContext.pageBuilder.transition = pages_transition;
				var defaultConnector_conf = (temp_configuration.getElementsByTagName('defaultConnector')[0]);
				if(defaultConnector_conf){
					defaultConnector_conf = defaultConnector_conf.textContent;
					try{
						var defConnClass = getClassFromName(defaultConnector_conf) ||
							getClassFromName(defaultConnector_conf, hiddenIfr.contentWindow);
						if(!defConnClass)
							throw new FrameworkException(defaultConnector_conf + ' isn\'t a valid GenericConnector');
						globalContext.defaultConnector = defaultConnector_conf ?
							new (defConnClass)() :
							new GenericConnector();
					}catch(e){
						log(e);
						globalContext.defaultConnector = new GenericConnector();
					}
				}else
					globalContext.defaultConnector = new GenericConnector();
				var accessController_conf = (temp_configuration.getElementsByTagName('accessController')[0]);
				var accesscontroller_promise = null;
				if(accessController_conf){
					var accessController_conf_name = accessController_conf.textContent;
					try{
						var accessControllerClass = getClassFromName(accessController_conf_name) ||
							getClassFromName(accessController_conf_name, hiddenIfr.contentWindow);
						if(!accessControllerClass)
							throw new FrameworkException(pageBuilder_conf + ' isn\'t a valid AccessController');
						globalContext.accessController = accessController_conf_name ?
							new (accessControllerClass)():
							new AccessController();
						accesscontroller_promise = globalContext.accessController.init(accessController_conf.getAttribute('method'));
					}catch(e){
						log(e);
						globalContext.accessController = new AccessController();
						accesscontroller_promise = globalContext.accessController.init(accessController_conf.getAttribute('method') || 'none')
					}
				}else{
					globalContext.accessController = new AccessController();
					accesscontroller_promise = globalContext.accessController.init('none');
				}
				globalContext.localDatabase = Database.getInstance();
				accesscontroller_promise.then(function(){
					var otherPromises = [];
					for(var sm of ModulePool.getModules()){
						var mContext = globalContext.clone();
						var mPerms = [];
						for(var mp of ModulePool.getModulePermissions(sm.name)){
							if(mp == 'pages'){
								mPerms = mPerms.concat(['PageFactory', 'PageConfiguration']);
							}else if(mp == 'users'){
								mPerms = mPerms.concat(['UserPool', 'RolePool']);
							}else if(mp == 'models'){
								mPerms = mPerms.concat(['ModelPool']);
							}
						}
						mContext.BobbleHead = new Proxy(BobbleHead, {
							whiteList: [
								'User',
								'Role',
								'Session',
								'Response',
								'Request',
								'ConnectorRequest',
								'Model',
								'ModelInstance',
								'Route',
								'Page',
								'PageContext',
								'AuthenticationMethod',
								'AuthenticationMethods',
								'VirtualPage',
								'Exceptions',
								'Errors',
								'Events',
								'Util',
								'XMLParser'
							].concat(mPerms),
							moduleName: sm.name,
							get: function(target, name) {
								if(name in target && this.whiteList.indexOf(name)!=-1)
									return target[name];
								else
									throw new FrameworkException('Unpermitted access to '+name+' from '+this.moduleName);
							}
						});
						var sandbox = new Sandbox(document.getElementById(hold_conf.container), mContext);
						var initReturn = sandbox.execMethod('init', [moduleConfs[sm.name]], sm);
						if(initReturn instanceof Promise)
							otherPromises.push(initReturn);
					}
					if(pages_index){
						hold_conf.index = parseInt(pages_index.getAttribute('vid'));
						var index_data = null;
						if(pages_index.getElementsByTagName('data')[0]){
							index_data = {};
							for(var c of (pages_index.getElementsByTagName('data')[0]).childNodes){
								if(c instanceof Element)
									index_data[c.tagName] = c.textContent;
							}
						}
						Promise.all(otherPromises).then(function(index,index_data){
							this.pageBuilder.buildPage(index,index_data);
						}.bind(globalContext,hold_conf.index,index_data));
					}
					this.initialization = false;
				}.bind(this));
			}.bind(this));
		}catch(e){
			log(e);
			throw new NotSupportedEngineError();
		}
	}
	static getConf(name){
		if(AppController.configuration)
			return AppController.configuration.getProperty(name);
		return null;
	}
};
AppController.configuration = null;<commit_msg>fixed module configuration parsing<commit_after>import XMLParser from './XMLParser.js';
import {log, absoluteURL, getClassFromName} from './Util.js';
import ModulePool from './ModulePool.js';
import ModelPool from './ModelPool.js';
import Router from './Router.js';
import Cacher from './Cacher.js';
import PageConfiguration from './PageConfiguration.js';
import Page from './Page.js';
import PageFactory from './PageFactory.js';
import GenericConfiguration from './GenericConfiguration.js';
import Route from './Route.js';
import ModuleConfiguration from './ModuleConfiguration.js';
import Context from './Context.js';
import PageBuilder from './PageBuilder.js';
import GenericConnector from './GenericConnector.js';
import AccessController from './AccessController.js';
import NotSupportedEngineError from './Errors/NotSupportedEngineError.js';
import Database from './Database.js';
import FrameworkException from './Exceptions/FrameworkException.js';
import Sandbox from 'js-sandbox';

export default class AppController{
	constructor(xmlConfiguration){
		this.moduleOnLoad = [];
		this.initialization = true;
		XMLParser.parseUrl(xmlConfiguration,this.processConf.bind(this));
	}
	registerModel(model){
		ModelPool.addModel(model);
	}
	registerModule(module){
		if(this.initialization)
			this.moduleOnLoad.push(module);
		else
			ModulePool.addModule(module);
	}
	registerRoute(route){
		Router.addRoute(route);
	}
	addToGlobalContext(name, obj){
		var globalContext = Context.getGlobal();
		if(name in globalContext)
			throw new FrameworkException('A module tried to edit global context!');
		else
			globalContext[name] = obj;
	}
	processConf(conf){
		if(!conf) return;
		var hold_conf = {};
		try{
			var temp_configuration = conf.getElementsByTagName('configuration')[0];
			hold_conf.container = (temp_configuration.getElementsByTagName('container')[0]).textContent;
			if((temp_configuration.getElementsByTagName('base_url')).length>0)
				hold_conf.base_url = (temp_configuration.getElementsByTagName('base_url')[0]).textContent;
			else{
				var path = document.location.pathname.split('/');
				path.pop();
				hold_conf.base_url = document.location.protocol + '//' + document.location.host + path.join('/');
			}
			var pageBuilder_conf = (temp_configuration.getElementsByTagName('pageBuilder')[0]);
			var cache_whitelist = [];
			var cache_blacklist = [];
			var cache_maxcached = 1000;
			var cacher_conf = (temp_configuration.getElementsByTagName('cacher')[0]);
			if(cacher_conf){
				if(cacher_conf.getAttribute('max-cached'))
					cache_maxcached = parseInt(cacher_conf.getAttribute('max-cached'));
				if(cacher_conf.getElementsByTagName('block'))
					for( var b of cacher_conf.getElementsByTagName('block')){
						cache_blacklist.push(b.getAttribute('url'));
					}
				if(cacher_conf.getElementsByTagName('persist'))
					for( var p of cacher_conf.getElementsByTagName('persist')){
						cache_whitelist.push(p.getAttribute('url'));
					}
			}
			var cacher_promise = Cacher.init(cache_maxcached, cache_whitelist, cache_blacklist);
			var page_container = temp_configuration.getElementsByTagName('pages')[0];
			var pages_index = page_container.getElementsByTagName('index')[0];
			var pages_path = page_container.getAttribute('path');
			var pages_transition = page_container.getAttribute('transition') || null;
			for( var p of page_container.getElementsByTagName('page')){
				var modulesAll = null;
				var rolesAllowed = null;
				if(p.getAttribute('modulesAllowed'))
					modulesAll = p.getAttribute('modulesAllowed').split(',');
				if(p.getAttribute('rolesAllowed'))
					rolesAllowed = p.getAttribute('rolesAllowed').split(',');
				var hold_vconf = {};
				if(p.getElementsByTagName('configuration') && p.getElementsByTagName('configuration').length > 0)
					for(var c of (p.getElementsByTagName('configuration')[0]).childNodes){
						if(c instanceof Element)
							hold_vconf[c.tagName] = c.textContent;
					}
				var confPage = new PageConfiguration(hold_vconf);
				var newPage = new Page(p.getAttribute('path'), //pages_path+
					parseInt(p.getAttribute('vid')),(p.getAttribute('noback')=='true'),confPage, modulesAll,
					(p.hasAttribute('keepLive')) ? (p.getAttribute('keepLive')=='true') : undefined,
					(p.hasAttribute('allowDuplicate')) ? (p.getAttribute('allowDuplicate')=='true') : undefined,
					(p.hasAttribute('ghostPage')) ? (p.getAttribute('ghostPage')=='true') : undefined, rolesAllowed);
				PageFactory.addPage(newPage);
			}
			AppController.configuration = new GenericConfiguration(hold_conf);
			var route_container = temp_configuration.getElementsByTagName('routes')[0];
			if(route_container){
				for( var r of route_container.getElementsByTagName('route')){
					this.registerRoute(new Route(r.getAttribute('entry'), r.getAttribute('destination')));
				}
			}
			var module_container = temp_configuration.getElementsByTagName('modules')[0];
			var current_promise = null;
			if(module_container){
				var modules_path = module_container.getAttribute('path');
				if(!modules_path.startsWith(hold_conf.base_url))
					modules_path = absoluteURL(hold_conf.base_url, modules_path, false);
				var moduleConfs = {};
				var hiddenIfr = document.createElement('iframe');
				hiddenIfr.style.display = 'none';
				document.body.appendChild(hiddenIfr);
				for(var v in window){
					if(!(v in hiddenIfr.contentWindow))
						hiddenIfr.contentWindow[v] = window[v];
				}
				hiddenIfr.contentWindow.Promise = window.Promise;
				hiddenIfr.contentWindow.Array = window.Array;
				hiddenIfr.contentWindow.Element = window.Element;
				hiddenIfr.contentWindow._document = new Proxy(document, {
					container: document.getElementById(hold_conf.container),
					whiteList: [
						'querySelector',
						'getElementById',
						'dispatchEvent',
						'createElement'
					],
					get: function(target, name) {
						var ret = ((typeof target[name] != 'function') || this.whiteList.indexOf(name)!=-1) ?
							target[name] :
							undefined;
						if(typeof ret == 'function' && name != 'createElement'){
							ret = function(next){
								var args = [];
								for(var i=1; i<arguments.length; i++)
									args[i-1] = arguments[i];
								var res = next.apply(document, args);
								if(res instanceof Node){
									var hold = res;
									while (hold = hold.parentNode)
										if (hold == this)
											return res;
									return this;
								}
							}.bind(this.container,ret);

						}
						return ret.bind(target);
					},
					set: function(obj, prop, value) {
						return false;
					}
				});
				for( var m of module_container.getElementsByTagName('module')){
					if(m.getAttribute('enabled') == 'true'){
						var hold_mconf = {};
						var modulePerm = m.getAttribute('permissions') ? m.getAttribute('permissions').split(',') : [];
						var xml2obj_func = function(ele){
							var hold_return = {};
							for(var c of ele.childNodes){
								if(c instanceof Element)
									if (c.hasChildNodes())
										if(c.childNodes.length == 1 && c.childNodes[0].nodeType == Node.TEXT_NODE)
											hold_return[c.tagName] = c.textContent;
										else
											hold_return[c.tagName] = xml2obj_func(c);
									else
										hold_return[c.tagName] = c.textContent;
							}
							return hold_return;
						};
						hold_mconf = xml2obj_func(m.getElementsByTagName('configuration')[0]);
						var confModule = new ModuleConfiguration(hold_mconf);
						current_promise = new Promise(
							function(confModule, modulePerm, current_promise, resolve, reject){
								var mod_load_func = function(confModule, modulePerm, resolve){
									var script = document.createElement("script");
									script.src = modules_path + m.getAttribute('path');
									script.type = 'module';
									script.onload = function(modules, configuration, permissions, callback){
										while(modules.length>0){
											var sm = modules.shift();
											moduleConfs[sm.name] = configuration;
											ModulePool.addModule(sm, permissions);
										}
										callback();
									}.bind(script, this.moduleOnLoad, confModule, modulePerm, resolve);
									if(modules_path.startsWith('file:')){
										var prefetchxhr = new XMLHttpRequest();
										prefetchxhr.onload = function(m, script, hiddenIfr, e){
											let blob = prefetchxhr.response;
											let newblob = new Blob([blob], {type: 'text/javascript'});
											script.src = URL.createObjectURL(newblob);
											hiddenIfr.contentDocument.head.appendChild(script);
										}.bind(this, m, script, hiddenIfr);
										prefetchxhr.open('get', modules_path + m.getAttribute('path'));
										prefetchxhr.responseType = 'blob';
										prefetchxhr.send();
									}else
										hiddenIfr.contentDocument.head.appendChild(script);
								}.bind(this, confModule, modulePerm, resolve);
								if(current_promise!=null)
									current_promise.then(mod_load_func);
								else
									mod_load_func();
							}.bind(this, confModule, modulePerm, current_promise)
						).catch(function(e) {
							log(e);
						});
					}
				}
			}
			var newBase = document.createElement("base");
			newBase.setAttribute("href", pages_path);
			document.getElementsByTagName("head")[0].appendChild(newBase);
			var newBaseIfr = hiddenIfr.contentDocument.createElement("base");
			newBaseIfr.setAttribute("href", hold_conf.base_url+'/'+pages_path);
			hiddenIfr.contentDocument.getElementsByTagName("head")[0].appendChild(newBaseIfr);
			Promise.all([cacher_promise, current_promise]).then(function(){
				var globalContext = Context.getGlobal();
				globalContext.BobbleHead = new Proxy(BobbleHead, {
					whiteList: [
						'User',
						'Role',
						'Session',
						'Response',
						'Request',
						'ConnectorRequest',
						'Model',
						'ModelInstance',
						'Route',
						'Page',
						'PageContext',
						'AuthenticationMethod',
						'AuthenticationMethods',
						'PageFactory',
						'VirtualPage',
						'Exceptions',
						'Errors',
						'Events',
						'Util'
					],
					get: function(target, name) {
						return (name in target && this.whiteList.indexOf(name)!=-1) ?
							target[name] :
							null;
					}
				});
				if(pageBuilder_conf){
					pageBuilder_conf = pageBuilder_conf.textContent;
					try{
						var pageBuildClass = getClassFromName(pageBuilder_conf) ||
							getClassFromName(pageBuilder_conf, hiddenIfr.contentWindow);
						if(!pageBuildClass)
							throw new FrameworkException(pageBuilder_conf + ' isn\'t a valid PageBuilder');
						globalContext.pageBuilder = pageBuilder_conf ?
							new (pageBuildClass)() :
							new PageBuilder();
					}catch(e){
						log(e);
						globalContext.pageBuilder = new PageBuilder();
					}
				}else
					globalContext.pageBuilder = new PageBuilder();
				globalContext.pageBuilder.container = hold_conf.container;
				globalContext.pageBuilder.transition = pages_transition;
				var defaultConnector_conf = (temp_configuration.getElementsByTagName('defaultConnector')[0]);
				if(defaultConnector_conf){
					defaultConnector_conf = defaultConnector_conf.textContent;
					try{
						var defConnClass = getClassFromName(defaultConnector_conf) ||
							getClassFromName(defaultConnector_conf, hiddenIfr.contentWindow);
						if(!defConnClass)
							throw new FrameworkException(defaultConnector_conf + ' isn\'t a valid GenericConnector');
						globalContext.defaultConnector = defaultConnector_conf ?
							new (defConnClass)() :
							new GenericConnector();
					}catch(e){
						log(e);
						globalContext.defaultConnector = new GenericConnector();
					}
				}else
					globalContext.defaultConnector = new GenericConnector();
				var accessController_conf = (temp_configuration.getElementsByTagName('accessController')[0]);
				var accesscontroller_promise = null;
				if(accessController_conf){
					var accessController_conf_name = accessController_conf.textContent;
					try{
						var accessControllerClass = getClassFromName(accessController_conf_name) ||
							getClassFromName(accessController_conf_name, hiddenIfr.contentWindow);
						if(!accessControllerClass)
							throw new FrameworkException(pageBuilder_conf + ' isn\'t a valid AccessController');
						globalContext.accessController = accessController_conf_name ?
							new (accessControllerClass)():
							new AccessController();
						accesscontroller_promise = globalContext.accessController.init(accessController_conf.getAttribute('method'));
					}catch(e){
						log(e);
						globalContext.accessController = new AccessController();
						accesscontroller_promise = globalContext.accessController.init(accessController_conf.getAttribute('method') || 'none')
					}
				}else{
					globalContext.accessController = new AccessController();
					accesscontroller_promise = globalContext.accessController.init('none');
				}
				globalContext.localDatabase = Database.getInstance();
				accesscontroller_promise.then(function(){
					var otherPromises = [];
					for(var sm of ModulePool.getModules()){
						var mContext = globalContext.clone();
						var mPerms = [];
						for(var mp of ModulePool.getModulePermissions(sm.name)){
							if(mp == 'pages'){
								mPerms = mPerms.concat(['PageFactory', 'PageConfiguration']);
							}else if(mp == 'users'){
								mPerms = mPerms.concat(['UserPool', 'RolePool']);
							}else if(mp == 'models'){
								mPerms = mPerms.concat(['ModelPool']);
							}
						}
						mContext.BobbleHead = new Proxy(BobbleHead, {
							whiteList: [
								'User',
								'Role',
								'Session',
								'Response',
								'Request',
								'ConnectorRequest',
								'Model',
								'ModelInstance',
								'Route',
								'Page',
								'PageContext',
								'AuthenticationMethod',
								'AuthenticationMethods',
								'VirtualPage',
								'Exceptions',
								'Errors',
								'Events',
								'Util',
								'XMLParser'
							].concat(mPerms),
							moduleName: sm.name,
							get: function(target, name) {
								if(name in target && this.whiteList.indexOf(name)!=-1)
									return target[name];
								else
									throw new FrameworkException('Unpermitted access to '+name+' from '+this.moduleName);
							}
						});
						var sandbox = new Sandbox(document.getElementById(hold_conf.container), mContext);
						var initReturn = sandbox.execMethod('init', [moduleConfs[sm.name]], sm);
						if(initReturn instanceof Promise)
							otherPromises.push(initReturn);
					}
					if(pages_index){
						hold_conf.index = parseInt(pages_index.getAttribute('vid'));
						var index_data = null;
						if(pages_index.getElementsByTagName('data')[0]){
							index_data = {};
							for(var c of (pages_index.getElementsByTagName('data')[0]).childNodes){
								if(c instanceof Element)
									index_data[c.tagName] = c.textContent;
							}
						}
						Promise.all(otherPromises).then(function(index,index_data){
							this.pageBuilder.buildPage(index,index_data);
						}.bind(globalContext,hold_conf.index,index_data));
					}
					this.initialization = false;
				}.bind(this));
			}.bind(this));
		}catch(e){
			log(e);
			throw new NotSupportedEngineError();
		}
	}
	static getConf(name){
		if(AppController.configuration)
			return AppController.configuration.getProperty(name);
		return null;
	}
};
AppController.configuration = null;<|endoftext|>


<commit_before>'use strict';

var path = require('path');
var rest = require('./syncRest.js');
var Promise = require('bluebird');
var _ = require('lodash');
var core = require('../../core.js');
var spawn = require('child_process').spawn;
var S = require('string');

var logDebug = core.log.debug;

function Sync(ip) {
  this.ip = ip;
  this.address = ['http://', ip, ':60008'].join('');
}

Sync.prototype.getConfig = function() {
  return rest.config(this.address);
};

Sync.prototype.setConfig = function(config) {
  var self = this;
  logDebug('SYNC => SET CONFIG ' + self.address, config);
  return rest.configPost(this.address, config)
  .then(function() {
    return self.getConfig()
    .then(function(configOut) {
      logDebug('SYNC => SET CONFIG CHECK ' + self.address, config);
    });
  });
};

Sync.prototype.getDeviceId = function() {
  return rest.system(this.address)
    .then(function(systemInfo) {
      return systemInfo.myID;
    });
};

Sync.prototype.hint = function(deviceId) {
  return rest.hint(this.address, deviceId);
};

Sync.prototype.ping = function() {
  logDebug('SYNC => PING ' + this.address);
  return rest.ping(this.address);
};

Sync.prototype.wait = function() {
  var self = this;
  var interval = 1 * 1000;
  var attempts = 120;
  return new Promise(function(fulfill, reject) {
    var rec = function(attemptsLeft) {
      self.ping()
      .then(function() {
        fulfill();
      })
      .catch(function(err) {
        if (attemptsLeft === 0) {
          reject(new Error('SYNC => Connecting to ' + self.address +
            ' timed out after ' + attempts + ' tries.'));
        } else {
          setTimeout(function() {
            rec(attemptsLeft - 1);
          }, interval);
        }
      });
    };
    rec(attempts);
  });
};

Sync.prototype.addDevice = function(remoteSync) {
  var self = this;
  return Promise.join(
    self.getDeviceId(),
    remoteSync.getConfig(),
    function(deviceId, config) {
      var deviceAlreadyExists = _.find(config.Devices, function(device) {
        return device.DeviceID === deviceId;
      });
      if (deviceAlreadyExists === undefined) {
        var ip = (function() {
          if (self.ip === '127.0.0.1' || self.ip === '0.0.0.0') {
            return 'dynamic';
          } else {
            return self.ip;
          }
        })();
        var device = {
          DeviceID: deviceId,
          Name: deviceId,
          Addresses: [ip],
          Compression: true,
          CertName: '',
          Introducer: false
        };
        config.Devices.push(device);
      }
      return remoteSync.setConfig(config)
        .then(function() {
          logDebug('SYNC => Linking devices ' +
            deviceId + '<=>' + remoteSync.address);
        });
    });
};

Sync.prototype.clear = function() {
  var self = this;
  return self.getConfig()
    .then(function(config) {
      config.Devices = [];
      config.Folders = [];
      return self.setConfig(config);
    });
};

Sync.prototype.removeFolder = function(id) {
  var self = this;
  return self.getConfig()
    .then(function(config) {
      logDebug('SYNC => Removing folder ' + id + ' ' + self.address);
      var folders = _.filter(config.Folders, function(folder) {
        return folder.ID !== id;
      });
      config.Folders = folders;
      return self.setConfig(config);
    });
};

Sync.prototype.addFolder = function(id, path, remoteSync, overrideOptions) {
  var self = this;
  logDebug('SYNC => Adding folder ' + id + ' ' + self.address);
  var options = {
    ReadOnly: false,
    RescanIntervalS: 5,
    IgnorePerms: true,
    Versioning: {
      Type: '',
      Params: {}
    },
    LenientMtimes: false,
    Copiers: 1,
    Pullers: 16,
    Hashers: 0,
    Invalid: ''
  };
  return Promise.join(
    self.getDeviceId(),
    self.getConfig(),
    remoteSync.getDeviceId(),
    function(deviceId, config, remoteDeviceId) {
      var devices = _.map([deviceId, remoteDeviceId],
        function(x) { return {DeviceID: x}; });
      var folder = {
        ID: id,
        Path: path,
        Devices: devices,
        ReadOnly: false,
        RescanIntervalS: options.RescanIntervalS,
        IgnorePerms: options.IgnorePerms,
        Versioning: options.Versioning,
        LenientMtimes: options.LenientMtime,
        Copiers: 1,
        Pullers: 16,
        Hashers: 0,
        Invalid: ''
      };
      var folderAlreadyExists = _.find(config.Folders,
        function(folder) { return folder.ID === id; });
      if (folderAlreadyExists === undefined) {
        config.Folders.push(folder);
      } else {
        config.Folders[folder.ID] = folder;
      }
      return config;
    })
    .then(function(config) {
      return self.setConfig(config);
    })
    .then(function() {
      return logDebug('SYNC => Added folder ' + id + ' ' + self.address);
    });
};

Sync.prototype.shareFolder = function(name, remoteSync) {
  var self = this;
  return core.deps.call(function(appConfig) {
    var localPath = appConfig.codeRoot;
    var remotePath = '/' + name;
    return self.addFolder(name, localPath, remoteSync)
    .then(function() {
      return remoteSync.addFolder(name, remotePath, self);
    })
    .then(function() {
      return logDebug('SYNC => Folder shared: ' + JSON.stringify(localPath));
    });
  });
};

Sync.prototype.linkDevices = function(sync) {
  var self = this;
  return self.addDevice(sync)
    .then(function() {
      return sync.addDevice(self);
    });
};

Sync.prototype.isUp = function() {
  var self = this;
  return self.ping()
    .then(function(data) {
      return true;
    })
    .catch(function(err) {
      if (S(err.message).contains('connect ECONNREFUSED')) {
        return false;
      } else {
        throw err;
      }
    });
};

Sync.prototype.restart = function() {
  var self = this;
  logDebug('SYNC => attemping restart: ' + self.address);
  return rest.restart(self.address)
    .then(function() {
      logDebug('SYNC => restarting: ' + self.address);
    });
};

Sync.prototype.restartWait = function() {
  var self = this;
  logDebug('SYNC => waiting for restart to finish: ' + self.address);
  return self.restart()
  .then(function() {
    return self.wait()
    .then(function() {
      logDebug('SYNC => done restarting: ' + self.address);
    });
  });
};

Sync.prototype.shutdown = function() {
  var self = this;
  logDebug('SYNC => attempting shutdown: ' + self.address);
  return rest.shutdown(this.address)
  .then(function() {
    logDebug('SYNC => shutdown: ' + self.address);
  });
};

Sync.prototype.start = function() {
  var self = this;
  // @todo: this only works for local syncthing for now
  var sE = (process.platform === 'win32') ? 'syncthing.exe' : 'syncthing';
  var SYNCTHING_EXECUTABLE = path.join(
    core.deps.lookup('config').sysConfRoot, 'bin', sE
  );
  var SYNCTHING_CONFIG = path.join(
    core.deps.lookup('config').sysConfRoot, 'syncthing'
  );
  return new Promise(function(fulfill, reject) {
    // @todo: this needs to be made A LOT better
    spawn(SYNCTHING_EXECUTABLE, ['-home', SYNCTHING_CONFIG], {
      stdio: 'ignore', // piping all stdio to /dev/null
      detached: true
    }).unref();
    fulfill(true);
  })
  .then(function() {
    return self.wait();
  });
};

module.exports = Sync;
<commit_msg>Fixing bug where syncthing would always share a folder with the appContexts code dir, even if there were two differnt apps being shared, with one of them not being the appContext.<commit_after>'use strict';

var path = require('path');
var rest = require('./syncRest.js');
var Promise = require('bluebird');
var _ = require('lodash');
var core = require('../../core.js');
var app = require('../../app.js');
var spawn = require('child_process').spawn;
var S = require('string');

var logDebug = core.log.debug;

function Sync(ip) {
  this.ip = ip;
  this.address = ['http://', ip, ':60008'].join('');
}

Sync.prototype.getConfig = function() {
  return rest.config(this.address);
};

Sync.prototype.setConfig = function(config) {
  var self = this;
  logDebug('SYNC => SET CONFIG ' + self.address, config);
  return rest.configPost(this.address, config)
  .then(function() {
    return self.getConfig()
    .then(function(configOut) {
      logDebug('SYNC => SET CONFIG CHECK ' + self.address, config);
    });
  });
};

Sync.prototype.getDeviceId = function() {
  return rest.system(this.address)
    .then(function(systemInfo) {
      return systemInfo.myID;
    });
};

Sync.prototype.hint = function(deviceId) {
  return rest.hint(this.address, deviceId);
};

Sync.prototype.ping = function() {
  logDebug('SYNC => PING ' + this.address);
  return rest.ping(this.address);
};

Sync.prototype.wait = function() {
  var self = this;
  var interval = 1 * 1000;
  var attempts = 120;
  return new Promise(function(fulfill, reject) {
    var rec = function(attemptsLeft) {
      self.ping()
      .then(function() {
        fulfill();
      })
      .catch(function(err) {
        if (attemptsLeft === 0) {
          reject(new Error('SYNC => Connecting to ' + self.address +
            ' timed out after ' + attempts + ' tries.'));
        } else {
          setTimeout(function() {
            rec(attemptsLeft - 1);
          }, interval);
        }
      });
    };
    rec(attempts);
  });
};

Sync.prototype.addDevice = function(remoteSync) {
  var self = this;
  return Promise.join(
    self.getDeviceId(),
    remoteSync.getConfig(),
    function(deviceId, config) {
      var deviceAlreadyExists = _.find(config.Devices, function(device) {
        return device.DeviceID === deviceId;
      });
      if (deviceAlreadyExists === undefined) {
        var ip = (function() {
          if (self.ip === '127.0.0.1' || self.ip === '0.0.0.0') {
            return 'dynamic';
          } else {
            return self.ip;
          }
        })();
        var device = {
          DeviceID: deviceId,
          Name: deviceId,
          Addresses: [ip],
          Compression: true,
          CertName: '',
          Introducer: false
        };
        config.Devices.push(device);
      }
      return remoteSync.setConfig(config)
        .then(function() {
          logDebug('SYNC => Linking devices ' +
            deviceId + '<=>' + remoteSync.address);
        });
    });
};

Sync.prototype.clear = function() {
  var self = this;
  return self.getConfig()
    .then(function(config) {
      config.Devices = [];
      config.Folders = [];
      return self.setConfig(config);
    });
};

Sync.prototype.removeFolder = function(id) {
  var self = this;
  return self.getConfig()
    .then(function(config) {
      logDebug('SYNC => Removing folder ' + id + ' ' + self.address);
      var folders = _.filter(config.Folders, function(folder) {
        return folder.ID !== id;
      });
      config.Folders = folders;
      return self.setConfig(config);
    });
};

Sync.prototype.addFolder = function(id, path, remoteSync, overrideOptions) {
  var self = this;
  logDebug('SYNC => Adding folder ' + id + ' ' + self.address);
  var options = {
    ReadOnly: false,
    RescanIntervalS: 5,
    IgnorePerms: true,
    Versioning: {
      Type: '',
      Params: {}
    },
    LenientMtimes: false,
    Copiers: 1,
    Pullers: 16,
    Hashers: 0,
    Invalid: ''
  };
  return Promise.join(
    self.getDeviceId(),
    self.getConfig(),
    remoteSync.getDeviceId(),
    function(deviceId, config, remoteDeviceId) {
      var devices = _.map([deviceId, remoteDeviceId],
        function(x) { return {DeviceID: x}; });
      var folder = {
        ID: id,
        Path: path,
        Devices: devices,
        ReadOnly: false,
        RescanIntervalS: options.RescanIntervalS,
        IgnorePerms: options.IgnorePerms,
        Versioning: options.Versioning,
        LenientMtimes: options.LenientMtime,
        Copiers: 1,
        Pullers: 16,
        Hashers: 0,
        Invalid: ''
      };
      var folderAlreadyExists = _.find(config.Folders,
        function(folder) { return folder.ID === id; });
      if (folderAlreadyExists === undefined) {
        config.Folders.push(folder);
      } else {
        config.Folders[folder.ID] = folder;
      }
      return config;
    })
    .then(function(config) {
      return self.setConfig(config);
    })
    .then(function() {
      return logDebug('SYNC => Added folder ' + id + ' ' + self.address);
    });
};

Sync.prototype.shareFolder = function(name, remoteSync) {
  var self = this;
  return new Promise(function(fulfill, reject) {
    app.get(name, function(err, app) {
      if (err) {
        reject(err);
      } else {
        fulfill(app);
      }
    });
  })
  .then(function(app) {
    var localPath = app.config.codeRoot;
    var remotePath = '/' + name;
    return self.addFolder(name, localPath, remoteSync)
    .then(function() {
      return remoteSync.addFolder(name, remotePath, self);
    })
    .then(function() {
      return logDebug('SYNC => Folder shared: ' + JSON.stringify(localPath));
    });
  });
};

Sync.prototype.linkDevices = function(sync) {
  var self = this;
  return self.addDevice(sync)
    .then(function() {
      return sync.addDevice(self);
    });
};

Sync.prototype.isUp = function() {
  var self = this;
  return self.ping()
    .then(function(data) {
      return true;
    })
    .catch(function(err) {
      if (S(err.message).contains('connect ECONNREFUSED')) {
        return false;
      } else {
        throw err;
      }
    });
};

Sync.prototype.restart = function() {
  var self = this;
  logDebug('SYNC => attemping restart: ' + self.address);
  return rest.restart(self.address)
    .then(function() {
      logDebug('SYNC => restarting: ' + self.address);
    });
};

Sync.prototype.restartWait = function() {
  var self = this;
  logDebug('SYNC => waiting for restart to finish: ' + self.address);
  return self.restart()
  .then(function() {
    return self.wait()
    .then(function() {
      logDebug('SYNC => done restarting: ' + self.address);
    });
  });
};

Sync.prototype.shutdown = function() {
  var self = this;
  logDebug('SYNC => attempting shutdown: ' + self.address);
  return rest.shutdown(this.address)
  .then(function() {
    logDebug('SYNC => shutdown: ' + self.address);
  });
};

Sync.prototype.start = function() {
  var self = this;
  // @todo: this only works for local syncthing for now
  var sE = (process.platform === 'win32') ? 'syncthing.exe' : 'syncthing';
  var SYNCTHING_EXECUTABLE = path.join(
    core.deps.lookup('config').sysConfRoot, 'bin', sE
  );
  var SYNCTHING_CONFIG = path.join(
    core.deps.lookup('config').sysConfRoot, 'syncthing'
  );
  return new Promise(function(fulfill, reject) {
    // @todo: this needs to be made A LOT better
    spawn(SYNCTHING_EXECUTABLE, ['-home', SYNCTHING_CONFIG], {
      stdio: 'ignore', // piping all stdio to /dev/null
      detached: true
    }).unref();
    fulfill(true);
  })
  .then(function() {
    return self.wait();
  });
};

module.exports = Sync;
<|endoftext|>


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

// 1) validate a zip file argument was supplied
// 2) unzip the zip file using node_appc
// 3) copy the "mobileweb" directory to "tizen"
// 4) remove tizen/templates/app/default/resources/mobileweb directory
// 4) copy tizen files (cli, templates, titanium) on top of "tizen" directory
// 5) copy titanium-sdk/lib/tiappxml.js on top of node_modules/titanium-sdk/lib
// 6) read manifest.json, parse json, add "tizen" to platforms, stringify json, write manifest
// 7) run dependencies.json builder using titanium_mobile/support/mobileweb/dependencyAnalyzer
// 8) re-zip distribution file with "VERSION-tizen.zip"

//input parameters:
// path to zip
// output file name
// working directory

console.log("cli args: " + process.argv);

var fs = require('fs'),
	path = require('path'),
	async = require('async'),
	appc = require('node-appc'),
	xmldom = require('xmldom'),
	wrench = require('wrench'),
	scriptArgs = process.argv.slice(2),
	workingDir = scriptArgs[1],
	titaniumTizenDir = __dirname,
	sdkRoot,
	resultPath,
	buildLinuxSdk = false;

console.log('[DEBUG] scriptArgs(zip, working directory): ' + scriptArgs);

async.series([
	function(next){
		//Validation
		if(validateArgs(scriptArgs)){
			var archiveName = path.basename(scriptArgs[0]);
			//build name for output zip with SDK
			archiveName = archiveName.replace('.zip', '-tizen.zip');
			resultPath = path.join(path.dirname(scriptArgs[0]), archiveName);
			if(resultPath.indexOf('linux') != -1){
				//initialize everything for linux sdk
				buildLinuxSdk = true;
			}
			console.log('[DEBUG] created output file name: ' + resultPath);
			next(null, 'ok');
		}
	}
	, function(next){
		console.log('Start unzip');
		//Unzip callback
		var resultCb = function(errorMsg){
			if(errorMsg){
				console.log('[DEBUG] unzip finished with error: ' + errorMsg);
				next(null, 'ok');
			}else{
				next(null, 'ok');
			}
		};
		if(process.platform === 'win32'){
			unzip7za(scriptArgs[0], scriptArgs[1], resultCb);
		}else{
			appc.zip.unzip(scriptArgs[0], scriptArgs[1], resultCb);
		}
	}
	, function(next){
		console.log('[DEBUG] Create tizen platform, initially copy it from mobileweb');
 		copymobilWebToTizen(function(){
 			console.log('[DEBUG] copymobilWebToTizen calling next()');
 			next(null, 'ok');
 		});
	}
	, function(next){
		console.log('[DEBUG] fixing manifest.json');
		fixManifest();
		next(null, 'ok');
	}, function(next){
		executeDependenciesAnalyzer(function(){
			next(null, 'ok');
		});
	}, function(next){
		if(process.platform === 'win32'){
			console.log('Start packaging on win32');
			packagingSDK7z(function(){
				next(null, 'ok');
			});
		} else {
			packagingSDKLinux(function(){
				next('Packaging on linux', null);
			});
		}
	}
	], function(err){
		if(err)
			console.log(err)
		console.log('Finished.')

});

//validating input parameters
function validateArgs(params){
	var workOk = true;
	if(!fs.existsSync(params[0])){
		console.log('Error: param 1 should point existng zip archive. Current value: ' + params[0]);
		workOk = false;
	}
	var stats = fs.statSync(params[1]);
	if(!stats.isDirectory() ){
		console.log('Error: param 3 should point existing directory. Current value: ' + params[1]);
		workOk = false;
	}
	return workOk;
}

function copymobilWebToTizen(finish){
	var basePath;
	if(buildLinuxSdk){
		basePath = path.join(workingDir, 'mobilesdk', 'linux');
	}else{
		basePath = path.join(workingDir, 'mobilesdk', 'win32');
	}
	console.log('[DEBUG] Looking for sdk in  folder:' + basePath);
	appc.fs.visitDirs(basePath,
		function(name, dpath){
			sdkRoot = dpath;
			console.log('[DEBUG] Full path to SDK folder:' + sdkRoot);
		},
		function(){
			//visitDirs finished, sdk root detected, do copy
			console.log('[DEBUG] wrench.copyDirSyncRecursive from ' + path.join(sdkRoot, 'mobileweb') + " to "+ path.join(sdkRoot, 'tizen'));
			wrench.copyDirSyncRecursive(path.join(sdkRoot, 'mobileweb'), path.join(sdkRoot, 'tizen'));

			console.log('[DEBUG] copyDirSyncRecursiveEx from ' +path.join(titaniumTizenDir, 'titanium', 'Ti') + " to "+ path.join(sdkRoot, 'tizen', 'titanium', 'Ti'));
			copyDirSyncRecursiveEx(path.join(titaniumTizenDir, 'titanium', 'Ti'), path.join(sdkRoot, 'tizen', 'titanium', 'Ti'));

			copyDirSyncRecursiveEx(path.join(titaniumTizenDir, 'cli', 'commands'), path.join(sdkRoot, 'tizen', 'cli', 'commands'));

			copyFileSync(path.join(titaniumTizenDir, 'titanium', 'Ti.js'), path.join(sdkRoot, 'tizen', 'titanium', 'Ti.js'));

			//remove tizen/templates/app/default/resources/mobileweb directory
			console.log('[DEBUG]rmdirSyncRecursive from ' + path.join(sdkRoot, 'tizen', 'templates', 'app', 'default', 'Resources', 'mobileweb'));
			wrench.rmdirSyncRecursive(path.join(sdkRoot, 'tizen', 'templates', 'app', 'default', 'Resources', 'mobileweb'), false);

			//config.tmpl template for
			copyFileSync(path.join(titaniumTizenDir, 'templates', 'app', 'config.tmpl'), path.join(sdkRoot, 'tizen', 'templates', 'app', 'config.tmpl'));

			wrench.copyDirSyncRecursive(path.join(titaniumTizenDir,'templates', 'app', 'default', 'Resources', 'tizen'), path.join(sdkRoot, 'tizen', 'templates', 'app', 'default', 'Resources', 'tizen'));

			copyFileSync(path.join(titaniumTizenDir, 'src', 'loader.js'), path.join(sdkRoot, 'tizen', 'src', 'loader.js'));

			copyDirSyncRecursiveEx(path.join(titaniumTizenDir, 'dependencyAnalyzer'), path.join(sdkRoot, 'tizen', 'dependencyAnalyzer'));

			//signer app for tizen
			fs.mkdirSync(path.join(sdkRoot, 'tizen', 'utils'));
			copyFileSync(path.join(titaniumTizenDir, 'utils', 'signapp.jar'), path.join(sdkRoot, 'tizen', 'utils', 'signapp.jar'));

			finish();
		}
	);
}

function fixManifest(){
	var manifestPath = path.join(sdkRoot, "manifest.json");
	var manifestStr = fs.readFileSync(manifestPath, 'utf8').toString();
	var manifestObject = JSON.parse(manifestStr);
	manifestObject.platforms.push("tizen");
	fs.writeFileSync(manifestPath, JSON.stringify(manifestObject), 'utf8');
}

function executeDependenciesAnalyzer(finished){
	console.log('[DEBUG] executeDependenciesAnalyzer ');
	var runner = require('child_process');
	var scriptpath = path.join(sdkRoot, 'tizen', 'dependencyAnalyzer', 'dependencyAnalyzer.js');
	var analyzerCmd = 'node "' + scriptpath + '"';

	console.log('starting dependency analyzer: ' + analyzerCmd);
	options = { cwd: path.join(sdkRoot, 'tizen', 'dependencyAnalyzer') };
	runner.exec(
		analyzerCmd,
		function (err, stdout, stderr) {
			console.log(stdout);
			if(err != null){
				console.log('[Error] executeDependenciesAnalyzer failed');
				console.log(stderr);
			}else{
				console.log('executeDependenciesAnalyzer ok');
			}
			finished();
		});
}

function copyFileSync(srcFile, destFile) {
	console.log('[DEBUG] copyFileSync from ' + srcFile + " to "+ destFile);
	var bytesRead, fdr, fdw, pos;
	var BUF_LENGTH = 64 * 1024;
	var _buff = new Buffer(BUF_LENGTH);
	fdr = fs.openSync(srcFile, 'r');
	fdw = fs.openSync(destFile, 'w');
	bytesRead = 1;
	pos = 0;
	while (bytesRead > 0) {
		bytesRead = fs.readSync(fdr, _buff, 0, BUF_LENGTH, pos);
		fs.writeSync(fdw, _buff, 0, bytesRead);
		pos += bytesRead;
	}
	fs.closeSync(fdr);
	return fs.closeSync(fdw);
}

function copyDirSyncRecursiveEx(sourceDir, newDirLocation) {
	console.log('[DEBUG] copyDirSyncRecursiveEx src ' + sourceDir + " destination "+ newDirLocation);
    /*  Create the directory where all our junk is moving to; read the mode of the source directory and mirror it */
    var checkDir = fs.statSync(sourceDir);
    try {
    	if(!fs.existsSync(newDirLocation)){
        	fs.mkdirSync(newDirLocation, checkDir.mode);
    	}
    } catch (e) {
        //if the directory already exists, that's okay
        if (e.code !== 'EEXIST') throw e;
    }

    var files = fs.readdirSync(sourceDir);
	console.log('[DEBUG] copyDirSyncRecursiveEx created filelist for ' + sourceDir + " it contains "+ files.length);
    for(var i = 0; i < files.length; i++) {
        var currFile = fs.lstatSync(sourceDir + "/" + files[i]);
        if(currFile.isDirectory()) {
            /*  recursion this thing right on back. */
            copyDirSyncRecursiveEx(sourceDir + "/" + files[i], newDirLocation + "/" + files[i]);
        } else if(currFile.isSymbolicLink()) {
        	console.log('[WARRNING] copyDirSyncRecursiveEx symlink instead of file: ' + sourceDir + "/" + files[i]);
            var symlinkFull = fs.readlinkSync(sourceDir + "/" + files[i]);
            fs.symlinkSync(symlinkFull, newDirLocation + "/" + files[i]);
        } else {
            /*  At this point, we've hit a file actually worth copying... so copy it on over. */
            copyFileSync(sourceDir + "/" + files[i], newDirLocation + "/" + files[i])
        }
    }
}

function find7za(){
	var zippath = path.normalize(path.join(path.dirname(require.resolve('node-appc')), '..','tools','7zip','7za.exe'));
	console.log('7za.exe detected. Path is ' + path.normalize(zippath));

	if(fs.existsSync(zippath)){
		return zippath;
	}else{
		console.log('Not found 7za.exe path is wrong ' + path.normalize(zippath));
	}
}

function packagingSDK7z(finish){
	console.log('Packaging application into zip');
	var packer = require('child_process');
	// Create the tasks to unzip each entry in the zip file
	var child,
	stdout = '',
	stderr = '';

	child = packer.spawn(path.resolve(find7za().toString()), ['a', resultPath, workingDir + '/*', '-tzip']);
	child.stdout.on('data', function (data) {
		stdout += data.toString();
	});
	child.on('exit', function (code, signal) {
		if (finish) {
			if (code) {
				// if we're on windows, the error message is actually in stdout, so scan for it
				if (process.platform === 'win32') {
					var foundError = false,
						err = [];

					stdout.split('\n').forEach(function (line) {
						if (/^Error\:/.test(line)) {
							foundError = true;
						}
						if (foundError) {
							line && err.push(line.trim());
						}
					});
					if (err.length) {
						stderr = err.join('\n') + stderr;
					}
				}
				finish();
			} else {
				finish();
			}
		}
	});
}

function unzip7za(src, dest, callback){
	var packer = require('child_process');
	// Create the tasks to unzip each entry in the zip file
	var child,
	stdout = '',
	stderr = '';

	child = packer.spawn(path.resolve(find7za().toString()), ['x', src, '-o' + dest, '-y', '-bd']);
	child.stdout.on('data', function (data) {
		stdout += data.toString();
	});
	child.on('exit', function (code, signal) {
		if (callback) {
			if (code) {
				// if we're on windows, the error message is actually in stdout, so scan for it
				if (process.platform === 'win32') {
					var foundError = false,
						err = [];

					stdout.split('\n').forEach(function (line) {
						if (/^Error\:/.test(line)) {
							foundError = true;
						}
						if (foundError) {
							line && err.push(line.trim());
						}
					});

					if (err.length) {
						stderr = err.join('\n') + stderr;
					}
				}
				callback(null);
			} else {
				callback(null);
			}
		}
	});
}

function packagingSDKLinux(finish){
	var packer = require('child_process');
	var cmdzip = 'zip -r "' + resultPath + '" *';
	console.log('zip cmd: ' + cmdzip);
	packer.exec(
		cmdzip,
		{
			cwd: workingDir
		},
		function (err, stdout, stderr) {
			console.log(stdout);
			if(err != null){
				console.log(stderr);
			}else{
				console.log('compressing ok');
			}
			finish(null);
		});
}
<commit_msg>now it copies <titanium_sdk>\tizen\themes\default\UI\SearchBar\close.png file<commit_after>#!/usr/bin/env node

// 1) validate a zip file argument was supplied
// 2) unzip the zip file using node_appc
// 3) copy the "mobileweb" directory to "tizen"
// 4) remove tizen/templates/app/default/resources/mobileweb directory
// 4) copy tizen files (cli, templates, titanium) on top of "tizen" directory
// 5) copy titanium-sdk/lib/tiappxml.js on top of node_modules/titanium-sdk/lib
// 6) read manifest.json, parse json, add "tizen" to platforms, stringify json, write manifest
// 7) run dependencies.json builder using titanium_mobile/support/mobileweb/dependencyAnalyzer
// 8) re-zip distribution file with "VERSION-tizen.zip"

//input parameters:
// path to zip
// output file name
// working directory

console.log("cli args: " + process.argv);

var fs = require('fs'),
	path = require('path'),
	async = require('async'),
	appc = require('node-appc'),
	xmldom = require('xmldom'),
	wrench = require('wrench'),
	scriptArgs = process.argv.slice(2),
	workingDir = scriptArgs[1],
	titaniumTizenDir = __dirname,
	sdkRoot,
	resultPath,
	buildLinuxSdk = false;

console.log('[DEBUG] scriptArgs(zip, working directory): ' + scriptArgs);

async.series([
	function(next){
		//Validation
		if(validateArgs(scriptArgs)){
			var archiveName = path.basename(scriptArgs[0]);
			//build name for output zip with SDK
			archiveName = archiveName.replace('.zip', '-tizen.zip');
			resultPath = path.join(path.dirname(scriptArgs[0]), archiveName);
			if(resultPath.indexOf('linux') != -1){
				//initialize everything for linux sdk
				buildLinuxSdk = true;
			}
			console.log('[DEBUG] created output file name: ' + resultPath);
			next(null, 'ok');
		}
	}
	, function(next){
		console.log('Start unzip');
		//Unzip callback
		var resultCb = function(errorMsg){
			if(errorMsg){
				console.log('[DEBUG] unzip finished with error: ' + errorMsg);
				next(null, 'ok');
			}else{
				next(null, 'ok');
			}
		};
		if(process.platform === 'win32'){
			unzip7za(scriptArgs[0], scriptArgs[1], resultCb);
		}else{
			appc.zip.unzip(scriptArgs[0], scriptArgs[1], resultCb);
		}
	}
	, function(next){
		console.log('[DEBUG] Create tizen platform, initially copy it from mobileweb');
 		copymobilWebToTizen(function(){
 			console.log('[DEBUG] copymobilWebToTizen calling next()');
 			next(null, 'ok');
 		});
	}
	, function(next){
		console.log('[DEBUG] fixing manifest.json');
		fixManifest();
		next(null, 'ok');
	}, function(next){
		executeDependenciesAnalyzer(function(){
			next(null, 'ok');
		});
	}, function(next){
		if(process.platform === 'win32'){
			console.log('Start packaging on win32');
			packagingSDK7z(function(){
				next(null, 'ok');
			});
		} else {
			packagingSDKLinux(function(){
				next('Packaging on linux', null);
			});
		}
	}
	], function(err){
		if(err)
			console.log(err)
		console.log('Finished.')

});

//validating input parameters
function validateArgs(params){
	var workOk = true;
	if(!fs.existsSync(params[0])){
		console.log('Error: param 1 should point existng zip archive. Current value: ' + params[0]);
		workOk = false;
	}
	var stats = fs.statSync(params[1]);
	if(!stats.isDirectory() ){
		console.log('Error: param 3 should point existing directory. Current value: ' + params[1]);
		workOk = false;
	}
	return workOk;
}

function copymobilWebToTizen(finish){
	var basePath;
	if(buildLinuxSdk){
		basePath = path.join(workingDir, 'mobilesdk', 'linux');
	}else{
		basePath = path.join(workingDir, 'mobilesdk', 'win32');
	}
	console.log('[DEBUG] Looking for sdk in  folder:' + basePath);
	appc.fs.visitDirs(basePath,
		function(name, dpath){
			sdkRoot = dpath;
			console.log('[DEBUG] Full path to SDK folder:' + sdkRoot);
		},
		function(){
			//visitDirs finished, sdk root detected, do copy
			console.log('[DEBUG] wrench.copyDirSyncRecursive from ' + path.join(sdkRoot, 'mobileweb') + " to "+ path.join(sdkRoot, 'tizen'));
			wrench.copyDirSyncRecursive(path.join(sdkRoot, 'mobileweb'), path.join(sdkRoot, 'tizen'));

			console.log('[DEBUG] copyDirSyncRecursiveEx from ' +path.join(titaniumTizenDir, 'titanium', 'Ti') + " to "+ path.join(sdkRoot, 'tizen', 'titanium', 'Ti'));
			copyDirSyncRecursiveEx(path.join(titaniumTizenDir, 'titanium', 'Ti'), path.join(sdkRoot, 'tizen', 'titanium', 'Ti'));

			copyDirSyncRecursiveEx(path.join(titaniumTizenDir, 'cli', 'commands'), path.join(sdkRoot, 'tizen', 'cli', 'commands'));

			copyFileSync(path.join(titaniumTizenDir, 'titanium', 'Ti.js'), path.join(sdkRoot, 'tizen', 'titanium', 'Ti.js'));

			//remove tizen/templates/app/default/resources/mobileweb directory
			console.log('[DEBUG]rmdirSyncRecursive from ' + path.join(sdkRoot, 'tizen', 'templates', 'app', 'default', 'Resources', 'mobileweb'));
			wrench.rmdirSyncRecursive(path.join(sdkRoot, 'tizen', 'templates', 'app', 'default', 'Resources', 'mobileweb'), false);

			//config.tmpl template for
			copyFileSync(path.join(titaniumTizenDir, 'templates', 'app', 'config.tmpl'), path.join(sdkRoot, 'tizen', 'templates', 'app', 'config.tmpl'));

			wrench.copyDirSyncRecursive(path.join(titaniumTizenDir,'templates', 'app', 'default', 'Resources', 'tizen'), path.join(sdkRoot, 'tizen', 'templates', 'app', 'default', 'Resources', 'tizen'));

			copyFileSync(path.join(titaniumTizenDir, 'src', 'loader.js'), path.join(sdkRoot, 'tizen', 'src', 'loader.js'));

			copyDirSyncRecursiveEx(path.join(titaniumTizenDir, 'dependencyAnalyzer'), path.join(sdkRoot, 'tizen', 'dependencyAnalyzer'));

			copyDirSyncRecursiveEx(path.join(titaniumTizenDir, 'themes'), path.join(sdkRoot, 'tizen', 'themes'));

			//signer app for tizen
			fs.mkdirSync(path.join(sdkRoot, 'tizen', 'utils'));
			copyFileSync(path.join(titaniumTizenDir, 'utils', 'signapp.jar'), path.join(sdkRoot, 'tizen', 'utils', 'signapp.jar'));

			finish();
		}
	);
}

function fixManifest(){
	var manifestPath = path.join(sdkRoot, "manifest.json");
	var manifestStr = fs.readFileSync(manifestPath, 'utf8').toString();
	var manifestObject = JSON.parse(manifestStr);
	manifestObject.platforms.push("tizen");
	fs.writeFileSync(manifestPath, JSON.stringify(manifestObject), 'utf8');
}

function executeDependenciesAnalyzer(finished){
	console.log('[DEBUG] executeDependenciesAnalyzer ');
	var runner = require('child_process');
	var scriptpath = path.join(sdkRoot, 'tizen', 'dependencyAnalyzer', 'dependencyAnalyzer.js');
	var analyzerCmd = 'node "' + scriptpath + '"';

	console.log('starting dependency analyzer: ' + analyzerCmd);
	options = { cwd: path.join(sdkRoot, 'tizen', 'dependencyAnalyzer') };
	runner.exec(
		analyzerCmd,
		function (err, stdout, stderr) {
			console.log(stdout);
			if(err != null){
				console.log('[Error] executeDependenciesAnalyzer failed');
				console.log(stderr);
			}else{
				console.log('executeDependenciesAnalyzer ok');
			}
			finished();
		});
}

function copyFileSync(srcFile, destFile) {
	console.log('[DEBUG] copyFileSync from ' + srcFile + " to "+ destFile);
	var bytesRead, fdr, fdw, pos;
	var BUF_LENGTH = 64 * 1024;
	var _buff = new Buffer(BUF_LENGTH);
	fdr = fs.openSync(srcFile, 'r');
	fdw = fs.openSync(destFile, 'w');
	bytesRead = 1;
	pos = 0;
	while (bytesRead > 0) {
		bytesRead = fs.readSync(fdr, _buff, 0, BUF_LENGTH, pos);
		fs.writeSync(fdw, _buff, 0, bytesRead);
		pos += bytesRead;
	}
	fs.closeSync(fdr);
	return fs.closeSync(fdw);
}

function copyDirSyncRecursiveEx(sourceDir, newDirLocation) {
	console.log('[DEBUG] copyDirSyncRecursiveEx src ' + sourceDir + " destination "+ newDirLocation);
    /*  Create the directory where all our junk is moving to; read the mode of the source directory and mirror it */
    var checkDir = fs.statSync(sourceDir);
    try {
    	if(!fs.existsSync(newDirLocation)){
        	fs.mkdirSync(newDirLocation, checkDir.mode);
    	}
    } catch (e) {
        //if the directory already exists, that's okay
        if (e.code !== 'EEXIST') throw e;
    }

    var files = fs.readdirSync(sourceDir);
	console.log('[DEBUG] copyDirSyncRecursiveEx created filelist for ' + sourceDir + " it contains "+ files.length);
    for(var i = 0; i < files.length; i++) {
        var currFile = fs.lstatSync(sourceDir + "/" + files[i]);
        if(currFile.isDirectory()) {
            /*  recursion this thing right on back. */
            copyDirSyncRecursiveEx(sourceDir + "/" + files[i], newDirLocation + "/" + files[i]);
        } else if(currFile.isSymbolicLink()) {
        	console.log('[WARRNING] copyDirSyncRecursiveEx symlink instead of file: ' + sourceDir + "/" + files[i]);
            var symlinkFull = fs.readlinkSync(sourceDir + "/" + files[i]);
            fs.symlinkSync(symlinkFull, newDirLocation + "/" + files[i]);
        } else {
            /*  At this point, we've hit a file actually worth copying... so copy it on over. */
            copyFileSync(sourceDir + "/" + files[i], newDirLocation + "/" + files[i])
        }
    }
}

function find7za(){
	var zippath = path.normalize(path.join(path.dirname(require.resolve('node-appc')), '..','tools','7zip','7za.exe'));
	console.log('7za.exe detected. Path is ' + path.normalize(zippath));

	if(fs.existsSync(zippath)){
		return zippath;
	}else{
		console.log('Not found 7za.exe path is wrong ' + path.normalize(zippath));
	}
}

function packagingSDK7z(finish){
	console.log('Packaging application into zip');
	var packer = require('child_process');
	// Create the tasks to unzip each entry in the zip file
	var child,
	stdout = '',
	stderr = '';

	child = packer.spawn(path.resolve(find7za().toString()), ['a', resultPath, workingDir + '/*', '-tzip']);
	child.stdout.on('data', function (data) {
		stdout += data.toString();
	});
	child.on('exit', function (code, signal) {
		if (finish) {
			if (code) {
				// if we're on windows, the error message is actually in stdout, so scan for it
				if (process.platform === 'win32') {
					var foundError = false,
						err = [];

					stdout.split('\n').forEach(function (line) {
						if (/^Error\:/.test(line)) {
							foundError = true;
						}
						if (foundError) {
							line && err.push(line.trim());
						}
					});
					if (err.length) {
						stderr = err.join('\n') + stderr;
					}
				}
				finish();
			} else {
				finish();
			}
		}
	});
}

function unzip7za(src, dest, callback){
	var packer = require('child_process');
	// Create the tasks to unzip each entry in the zip file
	var child,
	stdout = '',
	stderr = '';

	child = packer.spawn(path.resolve(find7za().toString()), ['x', src, '-o' + dest, '-y', '-bd']);
	child.stdout.on('data', function (data) {
		stdout += data.toString();
	});
	child.on('exit', function (code, signal) {
		if (callback) {
			if (code) {
				// if we're on windows, the error message is actually in stdout, so scan for it
				if (process.platform === 'win32') {
					var foundError = false,
						err = [];

					stdout.split('\n').forEach(function (line) {
						if (/^Error\:/.test(line)) {
							foundError = true;
						}
						if (foundError) {
							line && err.push(line.trim());
						}
					});

					if (err.length) {
						stderr = err.join('\n') + stderr;
					}
				}
				callback(null);
			} else {
				callback(null);
			}
		}
	});
}

function packagingSDKLinux(finish){
	var packer = require('child_process');
	var cmdzip = 'zip -r "' + resultPath + '" *';
	console.log('zip cmd: ' + cmdzip);
	packer.exec(
		cmdzip,
		{
			cwd: workingDir
		},
		function (err, stdout, stderr) {
			console.log(stdout);
			if(err != null){
				console.log(stderr);
			}else{
				console.log('compressing ok');
			}
			finish(null);
		});
}
<|endoftext|>


<commit_before>import { base } from '../config/constants'

export var push = (resolve, reject, data, collection) => {
    base.push(collection, {
        data: data
    }).then(snapshot => {
        resolve(snapshot)
    }).catch(err => {
        //handle error
        console.log(err)
    });
}

export var update = (resolve, reject, data, collection) => {
    base.update(collection, {
        data: data
    }).then(snapshot => {
        resolve(snapshot)
    }).catch(err => {
        //handle error
        console.log(err)
    });
}

export var post = (resolve, reject, data, collection) => {
    base.post(collection, {
        data: data
    }).then(snapshot => {
        resolve(snapshot)
    }).catch(err => {
        //handle error
        console.log(err)
    });
}

export var fetch = (resolve, reject, collection, query) => {
    query = query || {}
    base.fetch(collection, {
    context: {},
    asArray: true,
    queries: query
    }).then(snapshot => {
        resolve(snapshot);
    }).catch(err => {
        //handle error
        console.log(err)
    });
}

<commit_msg>removed empty lines<commit_after>import { base } from '../config/constants'

export var push = (resolve, reject, data, collection) => {
    base.push(collection, {
        data: data
    }).then(snapshot => {
        resolve(snapshot)
    }).catch(err => {
        //handle error
        console.log(err)
    });
}

export var update = (resolve, reject, data, collection) => {
    base.update(collection, {
        data: data
    }).then(snapshot => {
        resolve(snapshot)
    }).catch(err => {
        //handle error
        console.log(err)
    });
}

export var post = (resolve, reject, data, collection) => {
    base.post(collection, {
        data: data
    }).then(snapshot => {
        resolve(snapshot)
    }).catch(err => {
        //handle error
        console.log(err)
    });
}

export var fetch = (resolve, reject, collection, query) => {
    query = query || {}
    base.fetch(collection, {
    context: {},
    asArray: true,
    queries: query
    }).then(snapshot => {
        resolve(snapshot);
    }).catch(err => {
        //handle error
        console.log(err)
    });
}<|endoftext|>


<commit_before>define(function(require) {
  var module = require("ui/modules").get("kibana-chord");

  module.controller("ChordController", function($scope) {
    $scope.greeting = "Hello";
  });

  function ChordProvider(Private) {
    var TemplateVisType = Private(require("ui/template_vis_type/TemplateVisType"));

    return new TemplateVisType({
      name: "chord",
      title: "Chord Diagram",
      icon: "fa-pie-chart", // TODO make this look like a chord diagram
      description: "Visualize network flows with a Chord Diagram.",
      requiresSearch: true,
      template: require("plugins/kibana-chord/chord.html"),
      params: {
        editor: require("plugins/kibana-chord/chord-editor.html"),
        defaults: {
          textContent: "Kibana!"
        }
      }
    });
  }

  require("ui/registry/vis_types").register(ChordProvider);

  return ChordProvider;

});
<commit_msg>Specify weight, src, dest schemas<commit_after>define(function(require) {
  var module = require("ui/modules").get("kibana-chord");

  module.controller("ChordController", function($scope) {
    $scope.greeting = "Hello";
  });

  function ChordProvider(Private) {
    var TemplateVisType = Private(require("ui/template_vis_type/TemplateVisType"));

    return new TemplateVisType({
      name: "chord",
      title: "Chord Diagram",
      icon: "fa-pie-chart", // TODO make this look like a chord diagram
      description: "Visualize network flows with a Chord Diagram.",
      requiresSearch: true,
      template: require("plugins/kibana-chord/chord.html"),
      params: {
        editor: require("plugins/kibana-chord/chord-editor.html"),
        defaults: {
          textContent: "Kibana!"
        }
      },
      schemas: new Schemas([
        {
          group: "metrics",
          name: "weight",
          title: "Chord Weight",
          min: 1,
          max: 1,
          aggFilter: ["count", "sum"]
        },
        {
          group: "buckets",
          name: "src",
          title: "Chord Sources",
          min: 1,
          max: 1,
          aggFilter: "terms"
        },
        {
          group: "buckets",
          name: "dest",
          title: "Chord Destinations",
          min: 1,
          max: 1,
          aggFilter: "terms"
        }
      ])
    });
  }

  require("ui/registry/vis_types").register(ChordProvider);

  return ChordProvider;

});
<|endoftext|>


<commit_before>import React, {PureComponent} from 'react'
import PropTypes from 'prop-types'
import classNames from 'classnames'

class Button extends PureComponent {
  static displayName = 'Button'

  static propTypes = {
    accent: PropTypes.bool,
    children: PropTypes.node,
    className: PropTypes.string,
    compact: PropTypes.bool,
    dense: PropTypes.bool,
    primary: PropTypes.bool,
    raised: PropTypes.bool,
    ripple: PropTypes.bool,
  }

  render() {
    const {
      accent,
      children,
      className,
      compact,
      dense,
      primary,
      raised,
      ripple,
      ...otherProps,
    } = this.props
    const cssClasses = classNames({
      'mdc-button': true,
      'mdc-button--accent': accent,
      'mdc-button--compact': compact,
      'mdc-button--dense': dense,
      'mdc-button--primary': primary,
      'mdc-button--raised': raised,
    }, className)
    return (
      <button
        {...otherProps}
        className={cssClasses}
      >
        {children}
      </button>
    )
  }
}

export default Button
<commit_msg>fix(components): Add ripple for Button<commit_after>import React, {PureComponent} from 'react'
import PropTypes from 'prop-types'
import {MDCRipple} from '@material/ripple/dist/mdc.ripple'
import classNames from 'classnames'

class Button extends PureComponent {
  static displayName = 'Button'

  static propTypes = {
    accent: PropTypes.bool,
    children: PropTypes.node,
    className: PropTypes.string,
    compact: PropTypes.bool,
    dense: PropTypes.bool,
    primary: PropTypes.bool,
    raised: PropTypes.bool,
    ripple: PropTypes.bool,
  }

  render() {
    const {
      accent,
      children,
      className,
      compact,
      dense,
      primary,
      raised,
      ripple,
      ...otherProps,
    } = this.props
    const cssClasses = classNames({
      'mdc-button': true,
      'mdc-button--accent': accent,
      'mdc-button--compact': compact,
      'mdc-button--dense': dense,
      'mdc-button--primary': primary,
      'mdc-button--raised': raised,
    }, className)
    return (
      <button
        {...otherProps}
        className={cssClasses}
        {...(ripple ? {ref: el => (el && MDCRipple.attachTo(el))} : null)}
      >
        {children}
      </button>
    )
  }
}

export default Button
<|endoftext|>


<commit_before>/**
@module ember
@submodule ember-views
*/

var jQuery = Ember.imports.jQuery;
Ember.assert("Ember Views require jQuery 1.7 or 1.8", jQuery && (jQuery().jquery.match(/^1\.(7(?!$)(?!\.[01])|8)(\.\d+)?(pre|rc\d?)?/) || Ember.ENV.FORCE_JQUERY));

/**
  Alias for jQuery

  @method $
  @for Ember
*/
Ember.$ = jQuery;
<commit_msg>Less confusing failure message for jQuery 1.7 and 1.7.1 rejections<commit_after>/**
@module ember
@submodule ember-views
*/

var jQuery = Ember.imports.jQuery;
Ember.assert("Ember Views require jQuery 1.7 (>= 1.7.2) or 1.8", jQuery && (jQuery().jquery.match(/^1\.(7(?!$)(?!\.[01])|8)(\.\d+)?(pre|rc\d?)?/) || Ember.ENV.FORCE_JQUERY));

/**
  Alias for jQuery

  @method $
  @for Ember
*/
Ember.$ = jQuery;
<|endoftext|>