<commit_before>//
// Webble World 3.0 (IntelligentPad system for the web)
//
// Copyright (c) 2010-2015 Micke Nicander Kuwahara, Giannis Georgalis, Yuzuru Tanaka
//     in Meme Media R&D Group of Hokkaido University, Japan. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Additional restrictions may apply. See the LICENSE file for more information.
//

/**
 * @overview REST endpoints for creating zip archives from local directories.
 * @module api/files
 * @author Giannis Georgalis <jgeorgal@meme.hokudai.ac.jp>
 */

var Promise = require("bluebird");

var path = require('path');
var fs = require('fs');
var archiver = require('archiver');

Promise.promisifyAll(fs);

module.exports = function(app, config, mongoose, gettext, auth) {

	// Test with:
	// https://localhost:7443/api/files/zip/data/WebbleDevPack.zip
	//
	app.get('/api/files/zip/*', function (req, res) {

        var fullPath = req.params[0];

		var baseDir = path.dirname(fullPath);
		var baseName = path.basename(fullPath, '.zip');

        if (!baseDir || !baseName || baseDir.length == 0 || baseName.length == 0)
            return res.status(404).end();

        var directoryToZip = path.join(config.APP_ROOT_DIR, baseDir, baseName);

        return fs.statAsync(directoryToZip).then(function (stat) {

            if (!stat || !stat.isDirectory())
                res.status(404).end();
            else {

                var archive = archiver('zip');

                res.attachment(baseName + '.zip');
                archive.pipe(res);

                archive.directory(directoryToZip, baseName);
                archive.finalize();
            }

        }).catch(function (err) {

            //console.log(err);
            res.status(404).end();
        });
    });
};
<commit_msg>Quick fix for a security hole that was reported.<commit_after>//
// Webble World 3.0 (IntelligentPad system for the web)
//
// Copyright (c) 2010-2015 Micke Nicander Kuwahara, Giannis Georgalis, Yuzuru Tanaka
//     in Meme Media R&D Group of Hokkaido University, Japan. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Additional restrictions may apply. See the LICENSE file for more information.
//

/**
 * @overview REST endpoints for creating zip archives from local directories.
 * @module api/files
 * @author Giannis Georgalis <jgeorgal@meme.hokudai.ac.jp>
 */

var Promise = require("bluebird");

var path = require('path');
var fs = require('fs');
var archiver = require('archiver');

Promise.promisifyAll(fs);

module.exports = function(app, config, mongoose, gettext, auth) {

	// Test with:
	// https://localhost:7443/api/files/zip/data/WebbleDevPack.zip
	//
	app.get('/api/files/zip/*', function (req, res) {

        var fullPath = req.params[0];

		var baseDir = path.dirname(fullPath);
		var baseName = path.basename(fullPath, '.zip');

        if (!baseDir || !baseName || baseDir.length == 0 || baseName.length == 0)
            return res.status(404).end();

	    //-- this is not very safe (can zip and download any folder
	    //-- in the serverside installation app directory)
            // var directoryToZip = path.join(config.APP_ROOT_DIR, baseDir, baseName);

	    // this is pretty restrictive (only allows A to Z and
	    // numbers in filenamea and directory names, but let's be
	    // overly restrictive to avoid spending lots of time on
	    // sanitizing user input.
            directoryToZip = path.join(config.APP_ROOT_DIR, baseDir.replace(/[^A-Za-z0-9\/\\]/g, "_"), baseName.replace(/[^A-Za-z0-9]/g, "_"));

	    if(baseDir.substr(0, 4) != "data") { // everything we want people to download should be under this folder
		return res.status(404).end();
	    }

        return fs.statAsync(directoryToZip).then(function (stat) {

            if (!stat || !stat.isDirectory())
                res.status(404).end();
            else {

                var archive = archiver('zip');

                res.attachment(baseName + '.zip');
                archive.pipe(res);

                archive.directory(directoryToZip, baseName);
                archive.finalize();
            }

        }).catch(function (err) {

            //console.log(err);
            res.status(404).end();
        });
    });
};
<|endoftext|>


<commit_before>import React, { createRef } from 'react'

/**
 * Props:
 * zoom : 13 - higher the number, the more zoomed the map is on center
 * center: {lat:0.0, lng:0.0} - coordinates for center of map
 */

class MapComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      finalizedMarkers: new Map(),
      unfinalizedMarkers: new Map(),
      geoPaths: []
    }
    this.googleMapRef = createRef();
    this.googleMap = undefined
  }

  componentDidMount() {
    const loadGoogleMapScript = document.createElement('script');
    loadGoogleMapScript.src =
      'https://maps.googleapis.com/maps/api/js?key=' + process.env.REACT_APP_API_KEY + '&libraries=place';

    window.document.body.appendChild(loadGoogleMapScript);

    loadGoogleMapScript.addEventListener('load', () => {
      this.googleMap = this.createMap();
      let bounds = this.drawMap()
      this.googleMap.fitBounds(bounds);
    });
  }

  /*
   * Updates state with any changes in props
   */
  componentDidUpdate(prevProps) {
    if (prevProps !== this.props) {
      this.clearMap();
      this.drawMap();
    }
  }

  createMap() {
    return new window.google.maps.Map(this.googleMapRef.current, {
      zoom: this.props.zoom,
      center: this.props.center,
    })
  }

  addMarker(coordinates, type, label) {
    // TODO: firebase will provide coordinates as a GeoPoint --> convert to {lat, lng}
    // { lat: coordinates.lat(), lng: coordinates.lng() }

    var iconUrl;
    if (type === "flight") {
      iconUrl = "http://maps.google.com/mapfiles/ms/icons/blue-dot.png"
    } else if (type === "event") {
      iconUrl = "http://maps.google.com/mapfiles/ms/icons/green-dot.png"
    } else {
      iconUrl = "http://maps.google.com/mapfiles/ms/icons/red-dot.png"
    }

    var newMarker = new window.google.maps.Marker({
      position: coordinates,
      map: this.googleMap,
      animation: window.google.maps.Animation.DROP,
      icon: { url: iconUrl }
    })

    // zoom to marker when clicked
    newMarker.addListener('click', () => {
      this.googleMap.setZoom(15);
      this.googleMap.setCenter(newMarker.getPosition());

      // TODO: this.props.onMarkerClicked(id) --> notifies parent that marker clicked
    });

    return newMarker;
  }

  // constructs path object and places on map. Returns path object.
  addPath(map, path) {
    // dotted line
    var lineSymbol = {
      path: 'M 0,-1 0,1',
      strokeOpacity: 1,
      scale: 4
    };

    let geoPath = new window.google.maps.Polyline({
      path: path,
      strokeColor: '#FF0000',
      strokeOpacity: 0,
      strokeWeight: 2,
      icons: [{
          icon: lineSymbol,
          offset: '0',
          repeat: '20px'
        }]
    });

    geoPath.setMap(map);

    return geoPath;
  }

  /*
   * Given a list of travel object data, draws corresponding markers on map and
   * returns hash map containing marker objects
   */
  drawMarkers(list, bounds) {
    // construct hashmap with key: travelObject id, value: marker object
    return list.reduce((hashMap, item) => {
      if (item.type !== "flight") {
        hashMap.set(item.id, {marker: this.addMarker(item.coordinates, item.type, item.id), type: item.type});
        bounds.extend(item.coordinates);
      } else {
        hashMap.set(item.id, {
          marker: {
            departure: this.addMarker(item.departureCoordinates, item.type, item.id),
            arrival: this.addMarker(item.arrivalCoordinates, item.type, item.id)
          }, type: item.type});

        bounds.extend(item.departureCoordinates);
        bounds.extend(item.arrivalCoordinates);
      }
      return hashMap;
    }, new Map())
  }

  /*
   *  Draws path between all finalized travel objects, returns list of path objects
   */
  drawPaths() {
    // Separate into different segments
    var paths = [];
    var curPath = [];

    for (let i = 0; i < this.props.finalized.length; i++) {
      let item = this.props.finalized[i];

      // found flight -> create new path segment
      if (item.type === "flight") {
        if (paths.length !== 0) {
          curPath.push(item.departureCoordinates)
          paths.push(curPath);
        }
        curPath = [item.arrivalCoordinates];
      } else {
        curPath.push(item.coordinates);
        paths.push(curPath);
        curPath = [item.coordinates];
      }
    }

    // add remaining path, if any, to paths
    if (curPath.length > 1) {
      paths.push(curPath);
    }

    console.log(paths)

    // add each path to the map and return array of path objects
    return paths.map((path) => {
      return this.addPath(this.googleMap, path);
    })
  }

  drawMap() {
    var bounds = new window.google.maps.LatLngBounds();

    let unfinalizedMarkers = this.drawMarkers(this.props.unfinalized, bounds);
    let finalizedMarkers = this.drawMarkers(this.props.finalized, bounds);

    let pathArr = this.drawPaths();

    this.setState({
      unfinalizedMarkers: unfinalizedMarkers,
      finalizedMarkers: finalizedMarkers,
      geoPaths: pathArr
    });

    return bounds;
  }

  removeAllMarkers(hashMap) {
    for (const [key, value] of hashMap) {
      if (value.type !== "flight") {
        value.marker.setMap(null);
      } else {
        value.marker.departure.setMap(null);
        value.marker.arrival.setMap(null);
      }
    }
  }

  clearMap() {
    this.removeAllMarkers(this.state.unfinalizedMarkers);
    this.removeAllMarkers(this.state.finalizedMarkers);

    // remove all paths
    this.state.geoPaths.map((path) => path.setMap(null));
  }

  render() {
    return (
      <div
        id='map'
        ref={this.googleMapRef}
      />
    )
  }
}

export default MapComponent;<commit_msg>Add TODO<commit_after>import React, { createRef } from 'react'

/**
 * Props:
 * zoom : 13 - higher the number, the more zoomed the map is on center
 * center: {lat:0.0, lng:0.0} - coordinates for center of map
 */

class MapComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      finalizedMarkers: new Map(),
      unfinalizedMarkers: new Map(),
      geoPaths: []
    }
    this.googleMapRef = createRef();
    this.googleMap = undefined
  }

  componentDidMount() {
    const loadGoogleMapScript = document.createElement('script');
    loadGoogleMapScript.src =
      'https://maps.googleapis.com/maps/api/js?key=' + process.env.REACT_APP_API_KEY + '&libraries=place';

    window.document.body.appendChild(loadGoogleMapScript);

    loadGoogleMapScript.addEventListener('load', () => {
      this.googleMap = this.createMap();
      let bounds = this.drawMap()
      this.googleMap.fitBounds(bounds);
    });
  }

  /*
   * Updates state with any changes in props
   */
  componentDidUpdate(prevProps) {
    if (prevProps !== this.props) {
      this.clearMap();
      this.drawMap();
    }
  }

  createMap() {
    return new window.google.maps.Map(this.googleMapRef.current, {
      zoom: this.props.zoom,
      center: this.props.center,
    })
  }

  addMarker(coordinates, type, label) {
    // TODO: firebase will provide coordinates as a GeoPoint --> convert to {lat, lng}
    // { lat: coordinates.lat(), lng: coordinates.lng() }

    var iconUrl;
    if (type === "flight") {
      iconUrl = "http://maps.google.com/mapfiles/ms/icons/blue-dot.png"
    } else if (type === "event") {
      iconUrl = "http://maps.google.com/mapfiles/ms/icons/green-dot.png"
    } else {
      iconUrl = "http://maps.google.com/mapfiles/ms/icons/red-dot.png"
    }

    var newMarker = new window.google.maps.Marker({
      position: coordinates,
      map: this.googleMap,
      animation: window.google.maps.Animation.DROP,
      icon: { url: iconUrl }
    })

    // zoom to marker when clicked
    newMarker.addListener('click', () => {
      this.googleMap.setZoom(15);
      this.googleMap.setCenter(newMarker.getPosition());

      // TODO: this.props.onMarkerClicked(id) --> notifies parent that marker clicked
    });

    return newMarker;
  }

  // constructs path object and places on map. Returns path object.
  addPath(map, path) {
    // TODO : change to show directions between paths
    // dotted line
    var lineSymbol = {
      path: 'M 0,-1 0,1',
      strokeOpacity: 1,
      scale: 4
    };

    let geoPath = new window.google.maps.Polyline({
      path: path,
      strokeColor: '#FF0000',
      strokeOpacity: 0,
      strokeWeight: 2,
      icons: [{
          icon: lineSymbol,
          offset: '0',
          repeat: '20px'
        }]
    });

    geoPath.setMap(map);

    return geoPath;
  }

  /*
   * Given a list of travel object data, draws corresponding markers on map and
   * returns hash map containing marker objects
   */
  drawMarkers(list, bounds) {
    // construct hashmap with key: travelObject id, value: marker object
    return list.reduce((hashMap, item) => {
      if (item.type !== "flight") {
        hashMap.set(item.id, {marker: this.addMarker(item.coordinates, item.type, item.id), type: item.type});
        bounds.extend(item.coordinates);
      } else {
        hashMap.set(item.id, {
          marker: {
            departure: this.addMarker(item.departureCoordinates, item.type, item.id),
            arrival: this.addMarker(item.arrivalCoordinates, item.type, item.id)
          }, type: item.type});

        bounds.extend(item.departureCoordinates);
        bounds.extend(item.arrivalCoordinates);
      }
      return hashMap;
    }, new Map())
  }

  /*
   *  Draws path between all finalized travel objects, returns list of path objects
   */
  drawPaths() {
    // Separate into different segments
    var paths = [];
    var curPath = [];

    for (let i = 0; i < this.props.finalized.length; i++) {
      let item = this.props.finalized[i];

      // found flight -> create new path segment
      if (item.type === "flight") {
        if (paths.length !== 0) {
          curPath.push(item.departureCoordinates)
          paths.push(curPath);
        }
        curPath = [item.arrivalCoordinates];
      } else {
        curPath.push(item.coordinates);
        paths.push(curPath);
        curPath = [item.coordinates];
      }
    }

    // add remaining path, if any, to paths
    if (curPath.length > 1) {
      paths.push(curPath);
    }

    console.log(paths)

    // add each path to the map and return array of path objects
    return paths.map((path) => {
      return this.addPath(this.googleMap, path);
    })
  }

  drawMap() {
    var bounds = new window.google.maps.LatLngBounds();

    let unfinalizedMarkers = this.drawMarkers(this.props.unfinalized, bounds);
    let finalizedMarkers = this.drawMarkers(this.props.finalized, bounds);

    let pathArr = this.drawPaths();

    this.setState({
      unfinalizedMarkers: unfinalizedMarkers,
      finalizedMarkers: finalizedMarkers,
      geoPaths: pathArr
    });

    return bounds;
  }

  removeAllMarkers(hashMap) {
    for (const [key, value] of hashMap) {
      if (value.type !== "flight") {
        value.marker.setMap(null);
      } else {
        value.marker.departure.setMap(null);
        value.marker.arrival.setMap(null);
      }
    }
  }

  clearMap() {
    this.removeAllMarkers(this.state.unfinalizedMarkers);
    this.removeAllMarkers(this.state.finalizedMarkers);

    // remove all paths
    this.state.geoPaths.map((path) => path.setMap(null));
  }

  render() {
    return (
      <div
        id='map'
        ref={this.googleMapRef}
      />
    )
  }
}

export default MapComponent;<|endoftext|>


<commit_before>/**
 * Created by kishore on 4/25/16.
 */
var express = require("express");

var app = express();

console.log(__dirname + "/../client");
app.use(express.static(__dirname + "/../client"));

var ipaddress = "127.0.0.1";
var port = 4000;

app.listen(port, ipaddress);<commit_msg>fix(master): correct path serving static content<commit_after>/**
 * Created by kishore on 4/25/16.
 */
var express = require("express");

var app = express();

app.use(express.static(__dirname + "/.."));

var ipaddress = "127.0.0.1";
var port = 4000;

app.listen(port, ipaddress);<|endoftext|>


<commit_before>const fs = require('fs')
const path = require('path')
const {spawn} = require('child_process')
const {expandEnvironmentVariables} = require('../helpers/path')

const progressRegex = /([\d]{1,2}:[\d]{2}:[\d]{2}:[\d]{2})\s+(\(\d+\))/gi;
const durationRegex = /Duration:\s+([\d]{1,2}:[\d]{2}:[\d]{2}:[\d]{2})/gi;
const startRegex = /Start:\s+([\d]{1,2}:[\d]{2}:[\d]{2}:[\d]{2})/gi;

const option = (params, name, ...values) => {
    if (values !== undefined) {
        values.every(value => value !== undefined) ? params.push(name, ...values) : undefined
    }
}
const seconds = (string) => string.split(':')
    .map((e, i) => (i < 3) ? +e * Math.pow(60, 2 - i) : +e * 10e-6)
    .reduce((acc, val) => acc + val);

/**
 * This task creates rendering process
 */
module.exports = (job, settings) => {
    settings.logger.log(`[${job.uid}] rendering job...`);

    // create container for our parameters
    let params = [];
    let outputFile = expandEnvironmentVariables(job.output)

    // setup parameters
    params.push('-project', expandEnvironmentVariables(job.template.dest));
    params.push('-comp', job.template.composition);
    params.push('-output', outputFile);

    option(params, '-OMtemplate', job.template.outputModule);
    option(params, '-RStemplate', job.template.settingsTemplate);
    option(params, '-s', job.template.frameStart);
    option(params, '-e', job.template.frameEnd);
    option(params, '-i', job.template.incrementFrame);
    option(params, '-r', job.scriptfile);

    if (settings.multiFrames) params.push('-mp');
    if (settings.reuse) params.push('-reuse');
    if (job.template.continueOnMissing) params.push('-continueOnMissingFootage')

    if (settings.imageCachePercent || settings.maxMemoryPercent) {
        option(params, '-mem_usage', settings.imageCachePercent || 50, settings.maxMemoryPercent || 50);
    }

    // tracks progress
    let projectDuration = null;
    let currentProgress = null;
    let previousProgress = undefined;
    let renderStopwatch = null;
    let projectStart = null;

    const parse = (data) => {
        const string = ('' + data).replace(/;/g, ':'); /* sanitize string */

        // Only execute startRegex if project start hasnt been found
        const matchStart = isNaN(parseInt(projectStart)) ? startRegex.exec(string) : false;
        // Only execute durationRegex if project duration hasnt been found
        const matchDuration = isNaN(parseInt(projectDuration)) ? durationRegex.exec(string) : false;
        // Only execute progressRegex if project duration has been found
        const matchProgress = !isNaN(parseInt(projectDuration)) ? progressRegex.exec(string) : null;
        // If durationRegex has a match convert tstamp to seconds and define projectDuration only once
        projectDuration = (matchDuration) ? seconds(matchDuration[1]) : projectDuration;
        // If startRegex has a match convert tstamp to seconds and define projectStart only once
        projectStart = (matchStart) ? seconds(matchStart[1]) : projectStart;

        if (matchProgress) {
            currentProgress = Math.ceil((seconds(matchProgress[1]) - projectStart) * 100 / projectDuration);

            if (previousProgress !== currentProgress) {
                settings.logger.log(`[${job.uid}] rendering progress ${currentProgress}%...`);
                previousProgress = currentProgress;
                job.renderProgress = currentProgress;

                if (job.hasOwnProperty('onRenderProgress') && typeof job['onRenderProgress'] == 'function') {
                    job.onRenderProgress(job, job.renderProgress);
                }
            }
        }

        return data;
    }

    // spawn process and begin rendering
    return new Promise((resolve, reject) => {
        renderStopwatch = Date.now();

        if (settings.debug) {
            settings.logger.log(`[${job.uid}] spawning aerender process: ${settings.binary} ${params.join(' ')}`);
        }

        const output = [];
        const logPath = path.resolve(job.workpath, `../aerender-${job.uid}.log`)
        const instance = spawn(settings.binary, params, {
            // NOTE: disabled PATH for now, there were a few
            // issues related to plugins not working properly
            // env: { PATH: path.dirname(settings.binary) },
        });

        instance.on('error', err => reject(new Error(`Error starting aerender process: ${err}`)));
        instance.stdout.on('data', (data) => output.push(parse(data.toString('utf8'))));
        instance.stderr.on('data', (data) => output.push(data.toString('utf8')));

        /* on finish (code 0 - success, other - error) */
        instance.on('close', (code) => {
            const outputStr = output
                .map(a => '' + a).join('');

            if (code !== 0 && settings.stopOnError) {
                if (fs.existsSync(logPath)) {
                    settings.logger.log(`[${job.uid}] dumping aerender log:`)
                    settings.logger.log(fs.readFileSync(logPath, 'utf8'))
                }

                return reject(new Error(outputStr || 'aerender.exe failed to render the output into the file due to an unknown reason'));
            }

            settings.logger.log(`[${job.uid}] rendering took ~${(Date.now() - renderStopwatch) / 1000} sec.`);
            settings.logger.log(`[${job.uid}] writing aerender job log to: ${logPath}`);

            fs.writeFileSync(logPath, outputStr);

            /* resolve job without checking if file exists, or its size for image sequences */
            if (job.template.imageSequence || ['jpeg', 'jpg', 'png'].indexOf(outputFile) !== -1) {
                return resolve(job)
            }

            if (!fs.existsSync(outputFile)) {
                if (fs.existsSync(logPath)) {
                    settings.logger.log(`[${job.uid}] dumping aerender log:`)
                    settings.logger.log(fs.readFileSync(logPath, 'utf8'))
                }

                return reject(new Error(`Couldn't find a result file`))
            }

            const stats = fs.statSync(outputFile)

            /* file smaller than 1000 bytes */
            if (stats.size < 1000) {
                settings.logger.log(`[${job.uid}] Warning: output file size is less than 1000 bytes (${stats.size} bytes), be advised that file is corrupted, or rendering is still being finished`)
            }

            resolve(job)
        });
    })
};
<commit_msg>Add functionality to pipe stdout/stderr to logger<commit_after>const fs = require('fs')
const path = require('path')
const {spawn} = require('child_process')
const {expandEnvironmentVariables} = require('../helpers/path')

const progressRegex = /([\d]{1,2}:[\d]{2}:[\d]{2}:[\d]{2})\s+(\(\d+\))/gi;
const durationRegex = /Duration:\s+([\d]{1,2}:[\d]{2}:[\d]{2}:[\d]{2})/gi;
const startRegex = /Start:\s+([\d]{1,2}:[\d]{2}:[\d]{2}:[\d]{2})/gi;

const option = (params, name, ...values) => {
    if (values !== undefined) {
        values.every(value => value !== undefined) ? params.push(name, ...values) : undefined
    }
}
const seconds = (string) => string.split(':')
    .map((e, i) => (i < 3) ? +e * Math.pow(60, 2 - i) : +e * 10e-6)
    .reduce((acc, val) => acc + val);

/**
 * This task creates rendering process
 */
module.exports = (job, settings) => {
    settings.logger.log(`[${job.uid}] rendering job...`);

    // create container for our parameters
    let params = [];
    let outputFile = expandEnvironmentVariables(job.output)

    // setup parameters
    params.push('-project', expandEnvironmentVariables(job.template.dest));
    params.push('-comp', job.template.composition);
    params.push('-output', outputFile);

    option(params, '-OMtemplate', job.template.outputModule);
    option(params, '-RStemplate', job.template.settingsTemplate);
    option(params, '-s', job.template.frameStart);
    option(params, '-e', job.template.frameEnd);
    option(params, '-i', job.template.incrementFrame);
    option(params, '-r', job.scriptfile);

    if (settings.multiFrames) params.push('-mp');
    if (settings.reuse) params.push('-reuse');
    if (job.template.continueOnMissing) params.push('-continueOnMissingFootage')

    if (settings.imageCachePercent || settings.maxMemoryPercent) {
        option(params, '-mem_usage', settings.imageCachePercent || 50, settings.maxMemoryPercent || 50);
    }

    // tracks progress
    let projectDuration = null;
    let currentProgress = null;
    let previousProgress = undefined;
    let renderStopwatch = null;
    let projectStart = null;

    const parse = (data) => {
        const string = ('' + data).replace(/;/g, ':'); /* sanitize string */

        // Only execute startRegex if project start hasnt been found
        const matchStart = isNaN(parseInt(projectStart)) ? startRegex.exec(string) : false;
        // Only execute durationRegex if project duration hasnt been found
        const matchDuration = isNaN(parseInt(projectDuration)) ? durationRegex.exec(string) : false;
        // Only execute progressRegex if project duration has been found
        const matchProgress = !isNaN(parseInt(projectDuration)) ? progressRegex.exec(string) : null;
        // If durationRegex has a match convert tstamp to seconds and define projectDuration only once
        projectDuration = (matchDuration) ? seconds(matchDuration[1]) : projectDuration;
        // If startRegex has a match convert tstamp to seconds and define projectStart only once
        projectStart = (matchStart) ? seconds(matchStart[1]) : projectStart;

        if (matchProgress) {
            currentProgress = Math.ceil((seconds(matchProgress[1]) - projectStart) * 100 / projectDuration);

            if (previousProgress !== currentProgress) {
                settings.logger.log(`[${job.uid}] rendering progress ${currentProgress}%...`);
                previousProgress = currentProgress;
                job.renderProgress = currentProgress;

                if (job.hasOwnProperty('onRenderProgress') && typeof job['onRenderProgress'] == 'function') {
                    job.onRenderProgress(job, job.renderProgress);
                }
            }
        }

        return data;
    }

    // spawn process and begin rendering
    return new Promise((resolve, reject) => {
        renderStopwatch = Date.now();

        if (settings.debug) {
            settings.logger.log(`[${job.uid}] spawning aerender process: ${settings.binary} ${params.join(' ')}`);
        }

        const output = [];
        const logPath = path.resolve(job.workpath, `../aerender-${job.uid}.log`)
        const instance = spawn(settings.binary, params, {
            // NOTE: disabled PATH for now, there were a few
            // issues related to plugins not working properly
            // env: { PATH: path.dirname(settings.binary) },
        });

        instance.on('error', err => reject(new Error(`Error starting aerender process: ${err}`)));
        instance.stdout.on('data', (data) => {
            output.push(parse(data.toString('utf8')));
            (settings.verbose && settings.logger.log(data));
        });
        instance.stderr.on('data', (data) => {
            output.push(data.toString('utf8'));
            (settings.verbose && settings.logger.log(data));
        });

        /* on finish (code 0 - success, other - error) */
        instance.on('close', (code) => {
            const outputStr = output
                .map(a => '' + a).join('');

            if (code !== 0 && settings.stopOnError) {
                if (fs.existsSync(logPath)) {
                    settings.logger.log(`[${job.uid}] dumping aerender log:`)
                    settings.logger.log(fs.readFileSync(logPath, 'utf8'))
                }

                return reject(new Error(outputStr || 'aerender.exe failed to render the output into the file due to an unknown reason'));
            }

            settings.logger.log(`[${job.uid}] rendering took ~${(Date.now() - renderStopwatch) / 1000} sec.`);
            settings.logger.log(`[${job.uid}] writing aerender job log to: ${logPath}`);

            fs.writeFileSync(logPath, outputStr);

            /* resolve job without checking if file exists, or its size for image sequences */
            if (job.template.imageSequence || ['jpeg', 'jpg', 'png'].indexOf(outputFile) !== -1) {
                return resolve(job)
            }

            if (!fs.existsSync(outputFile)) {
                if (fs.existsSync(logPath)) {
                    settings.logger.log(`[${job.uid}] dumping aerender log:`)
                    settings.logger.log(fs.readFileSync(logPath, 'utf8'))
                }

                return reject(new Error(`Couldn't find a result file`))
            }

            const stats = fs.statSync(outputFile)

            /* file smaller than 1000 bytes */
            if (stats.size < 1000) {
                settings.logger.log(`[${job.uid}] Warning: output file size is less than 1000 bytes (${stats.size} bytes), be advised that file is corrupted, or rendering is still being finished`)
            }

            resolve(job)
        });
    })
};

<|endoftext|>


<commit_before>var express = require('express');

// Middleware
var morgan = require('morgan');
var parser = require('body-parser');
var cors = require('cors');
var process

// Router
var router = require('./routes.js');

//Port
var port = process.env.PORT || 3000;

var app = express();
module.exports.app = app;

// Set what we are listening on.
app.set("port", port);

//Taking care of cross-origin requests
app.use(cors());

// Logging and parsing
app.use(morgan('dev'));
app.use(parser.json());

// Set up our routes
app.use("/", router);

//Have to think about whether static serving is necessary in this context.

// If we are being run directly, run the server.
if (!module.parent) {
  app.listen(app.get("port"));
  console.log("Listening on", app.get("port"));
}<commit_msg>Require process<commit_after>var express = require('express');

// Middleware
var morgan = require('morgan');
var parser = require('body-parser');
var cors = require('cors');
var process = require('process');

// Router
var router = require('./routes.js');

//Port
console.log("process", process);
var port = process.env.PORT || 3000;

var app = express();
module.exports.app = app;

// Set what we are listening on.
app.set("port", port);

//Taking care of cross-origin requests
app.use(cors());

// Logging and parsing
app.use(morgan('dev'));
app.use(parser.json());

// Set up our routes
app.use("/", router);

//Have to think about whether static serving is necessary in this context.

// If we are being run directly, run the server.
if (!module.parent) {
  app.listen(app.get("port"));
  console.log("Listening on", app.get("port"));
}<|endoftext|>


<commit_before>// Load in our dependencies
var fs = require('fs');
var expect = require('chai').expect;
var tmp = require('tmp');
var ImageSet = require('../../server/image-set');
var httpUtils = require('./utils/http');
var serverUtils = require('./utils/server');

// Start our tests
describe('A request to POST /update-image-set/:filepath', function () {
  describe('for an existent filepath', function () {
    // Create a temporary ref file to update
    // DEV: We could use mocking for updating the file but this removes one more contract to maintain
    var currentFilepath = __dirname + '/../test-files/dot.png';
    var originalRefFilepath = __dirname + '/../test-files/checkerboard.png';
    before(function createTmpFile () {
      // Copy image to a temporary location
      // https://github.com/raszi/node-tmp/tree/v0.0.30#synchronous-file-creation
      this.tmpFile = tmp.fileSync();
      this.refFilepath = this.tmpFile.name;
      fs.writeFileSync(this.refFilepath, fs.readFileSync(originalRefFilepath));
    });
    after(function cleanupTmpFile () {
      this.tmpFile.removeCallback();
      delete this.tmpFile;
      delete this.refFilepath;
    });

    // Run a server
    before(function runServer () {
      // Run a server with our temporary file
      serverUtils._runBefore(ImageSet.generateSets([
        currentFilepath
      ], [
        this.refFilepath
      ], {
        diffImages: ['mock-image-1/diff.png']
      })).call(this);
    });
    after(serverUtils._runAfter());

    // Make our request
    before(function makeRequest (done) {
      var currentBase64Contents = 'data:image/png;base64,' + fs.readFileSync(currentFilepath).toString('base64');
      httpUtils._save({
        method: 'POST', url: serverUtils.getUrl('/update-image-set/' + encodeURIComponent(this.refFilepath)),
        form: {
          ref: currentBase64Contents
        },
        expectedStatusCode: 200
      }).call(this, done);
    });

    it('updated reference image with new contents', function () {
      var actualContents = fs.readFileSync(this.refFilepath);
      var expectedContents = fs.readFileSync(currentFilepath);
      expect(actualContents).to.deep.equal(expectedContents);
    });

    it('replies with imagesEqual info', function () {
      // DEV: We use a contract to guarantee consistency between browser/server tests
      // Set via: echo -n '{"imagesEqual":true}' > test/test-files/http-responses/update-image-set-filepath.json
      var expectedResponse = fs.readFileSync(
        __dirname + '/../test-files/http-responses/update-image-set-filepath.json', 'utf8');
      expect(this.body).to.deep.equal(expectedResponse);
    });
  });

  describe('for a non-existent filepath', function () {
    // Create our server and make our request
    serverUtils.run([]);
    httpUtils.save({
      method: 'POST', url: serverUtils.getUrl('/update-image-set/does-not-exist.png'),
      expectedStatusCode: 404
    });

    it('receives a 404', function () {
      // Assert provided by `expectedStatusCode`
    });
  });
});
<commit_msg>Fixed up diff image<commit_after>// Load in our dependencies
var fs = require('fs');
var expect = require('chai').expect;
var tmp = require('tmp');
var ImageSet = require('../../server/image-set');
var httpUtils = require('./utils/http');
var serverUtils = require('./utils/server');

// Start our tests
describe('A request to POST /update-image-set/:filepath', function () {
  describe('for an existent filepath', function () {
    // Create a temporary ref file to update
    // DEV: We could use mocking for updating the file but this removes one more contract to maintain
    var currentFilepath = __dirname + '/../test-files/dot.png';
    var originalRefFilepath = __dirname + '/../test-files/checkerboard.png';
    before(function createTmpFile () {
      // Copy image to a temporary location
      // https://github.com/raszi/node-tmp/tree/v0.0.30#synchronous-file-creation
      this.tmpFile = tmp.fileSync();
      this.refFilepath = this.tmpFile.name;
      fs.writeFileSync(this.refFilepath, fs.readFileSync(originalRefFilepath));
    });
    after(function cleanupTmpFile () {
      this.tmpFile.removeCallback();
      delete this.tmpFile;
      delete this.refFilepath;
    });

    // Run a server
    before(function runServer () {
      // Run a server with our temporary file
      serverUtils._runBefore(ImageSet.generateSets([
        currentFilepath
      ], [
        this.refFilepath
      ], {
        diffImages: ['/dev/null']
      })).call(this);
    });
    after(serverUtils._runAfter());

    // Make our request
    before(function makeRequest (done) {
      var currentBase64Contents = 'data:image/png;base64,' + fs.readFileSync(currentFilepath).toString('base64');
      httpUtils._save({
        method: 'POST', url: serverUtils.getUrl('/update-image-set/' + encodeURIComponent(this.refFilepath)),
        form: {
          ref: currentBase64Contents
        },
        expectedStatusCode: 200
      }).call(this, done);
    });

    it('updated reference image with new contents', function () {
      var actualContents = fs.readFileSync(this.refFilepath);
      var expectedContents = fs.readFileSync(currentFilepath);
      expect(actualContents).to.deep.equal(expectedContents);
    });

    it('replies with imagesEqual info', function () {
      // DEV: We use a contract to guarantee consistency between browser/server tests
      // Set via: echo -n '{"imagesEqual":true}' > test/test-files/http-responses/update-image-set-filepath.json
      var expectedResponse = fs.readFileSync(
        __dirname + '/../test-files/http-responses/update-image-set-filepath.json', 'utf8');
      expect(this.body).to.deep.equal(expectedResponse);
    });
  });

  describe('for a non-existent filepath', function () {
    // Create our server and make our request
    serverUtils.run([]);
    httpUtils.save({
      method: 'POST', url: serverUtils.getUrl('/update-image-set/does-not-exist.png'),
      expectedStatusCode: 404
    });

    it('receives a 404', function () {
      // Assert provided by `expectedStatusCode`
    });
  });
});
<|endoftext|>


<commit_before>angular.module('Samson.DataGrid')
    .directive('datagrid', function() {
        var directiveDefinitionObject = {
            restrict: 'E',
            transclude: true,
            scope: 'isolate',
            templateUrl: '/bundles/samsondatagrid/views/datagrid.html',
            replace: true,
            compile: function(tElement, tAttr) {
                if ('ngRowController' in tAttr) {
                    tElement.find('tbody[ng-repeat]').attr('ng-controller', tAttr.ngRowController);
                }

                return function($scope, iElement, iAttr) {
                    var data = null;

                    if ('headerTemplate' in iAttr) {
                        $scope.headerTemplate = iAttr['headerTemplate'];
                    }
                    if ('bodyTemplate' in iAttr) {
                        $scope.bodyTemplate = iAttr['bodyTemplate'];
                    }
                    if ('formTemplate' in iAttr) {
                        $scope.formTemplate = iAttr['formTemplate'];
                    }
                    if ('noResultsTemplate' in iAttr) {
                        $scope.noResultsTemplate = iAttr['noResultsTemplate'];
                    }
                    if ('data' in iAttr) {
                        data = angular.fromJson(iAttr['data']);
                    }
                    if ('filterColumns' in iAttr) {
                        $scope.filterColumns = iAttr.filterColumns.split(',');
                    }
                    if ('service' in iAttr) {
                        $scope.dataService = iAttr.service;
                    }
                    if ('ngRowController' in iAttr) {
                        $scope.rowController = iAttr.ngRowController;
                    }
                    if ('filterTemplate' in iAttr){
                        $scope.filterTemplate = iAttr.filterTemplate;
                    }
                    if ('colgroupTemplate' in iAttr){
                        $scope.colgroupTemplate = iAttr.colgroupTemplate;
                    }
                    $scope.driver = $scope.instantiateDriver('driver' in iAttr ? iAttr['driver'] : 'clientside');

                    if(iAttr.routes) {
                        $scope.routes = $scope.$eval('{'+iAttr.routes+'}');
                    }
                    $scope.routeParams = {};
                    if (iAttr.routeParams) {
                        $scope.routeParams = $scope.$eval(iAttr.routeParams);
                    }
                    $scope.idMap = { id: 'row.id' };
                    if (iAttr.idMap) {
                        $scope.idMap = $scope.$eval(iAttr.idMap);
                    }

                    setTimeout(function() {
                        $scope.$apply(
                            function() {
                                var $headerCells = iElement.find('thead:eq(0) tr:eq(0)').find('th, td');
                                var count = 0;
                                $headerCells.each(function() {
                                    count += parseInt($(this).attr('colspan')) || 1;
                                });

                                $scope.columnCount = count;
                            }

                        );
                    });

                    var loadingEl = null;
                    $scope.$watch('loading', function(val) {
                        if (!val && loadingEl) {
                            setTimeout(function() {
                                loadingEl.width(iElement.find('.table').width()).height(iElement.find('.table').height());
                            }, 0);
                            loadingEl.fadeTo(500, 0, function() {
                                loadingEl.remove();
                                loadingEl = null;
                            })
                        } else if (val && !loadingEl) {
                            loadingEl = $("
").appendTo('body').css({ position: 'absolute', backgroundColor: 'white' }).position({ my: 'left top', at: 'left top', of: iElement.find('.table') })
                                .width(iElement.find('.table').width()).height(iElement.find('.table').height())
                                .fadeTo(0, 0).fadeTo(500, .85);
                        }
                    })

                    $scope.setData(data);
                }
            },
            controller: function($scope, $attrs, $templateCache, $injector, $parse, $q) {
                $scope.editing = [];
                $scope.newRows = [];

                this.getDataService = function() {
                    return $scope.dataService;
                }

                var self = this;
                $scope.headerTemplate = 'datagrid-no-header.html';
                $templateCache.put('datagrid-no-header.html', '
You need to define a header template!
');
                $scope.bodyTemplate = 'datagrid-no-body.html';
                $templateCache.put('datagrid-no-body.html', '
You need to define a body template!
');
                $scope.formTemplate = 'datagrid-no-form.html';
                $templateCache.put('datagrid-no-form.html', '
You need to define a form template!
');
                $scope.noResultsTemplate = 'datagrid-no-results.html';
                $templateCache.put('datagrid-no-results.html', 'No results	');
                $scope.driver = 'clientside';
                $scope.filterTemplate = '/bundles/samsondatagrid/views/filter.html';
                $scope.colgroupTemplate = null;

                $scope.visibleRows = [];

                $scope.$watch('filterColumns', function(newValue) {
                    callDriver('setFilterFields', newValue);
                })

                $scope.instantiateDriver = function(name) {
                    return $injector.instantiate(drivers[name]);
                }

                var getDriver = function() {
                    return $scope.driver;
                }
                var callDriver = function(method) {
                    driver = getDriver();
                    if (!(method in driver)) {
                        throw Error('The driver has no method '+method);
                    }
                    return driver[method].apply(driver, Array.prototype.slice.call(arguments, 1));
                }

                this.transform = function(data) {
                    if (!$scope.dataService) {
                        return data;
                    }

                    var service = $injector.get($scope.dataService);

                    return 'transformResponse' in service ? service.transformResponse(data) : data;
                }

                $scope.setData = function(data) {
                    if (null === data) {
                        service = $injector.get($scope.dataService);
                        if ('getData' in service) {
                            data = service.getData();
                        }
                    }

                    getDriver().loading = true;
                    $q.when(data).then(function(data) {
                        callDriver('setData', data, self.transform);
                        getDriver().loading = false;

                        self.updateData();
                    }, function(reason) {
                        throw Error('Error while fetching data: '+reason);
                    });
                }
                this.updateData = function() {
                    var properties = ['visibleRows', 'firstResult', 'lastResult', 'totalResults', 'filteredResults', 'page', 'pages', 'sort'];
                    for (var i in properties) {
                        var property = properties[i];
                        $scope[property] = callDriver('get'+ property.charAt(0).toUpperCase() + property.slice(1));
                    }

                    return;
                }

                $scope.setPage = function(page) {
                    var result = callDriver('setPage', page);

                    if (angular.isObject(result) && 'then' in result) {
                        result.then(function() {
                            self.updateData();
                        });

                        return;
                    }

                    self.updateData();
                }

                this.sort = function(sortField) {
                    var result = callDriver('sort', sortField);

                    if (angular.isObject(result) && 'then' in result) {
                        result.then(function() {
                            self.updateData();
                        });

                        return;
                    }

                    self.updateData();
                }

                $scope.isEditable = function(row) {
                    return $scope.visibleRows.indexOf(row) > -1;
                }

                var generateParams = function(extraParams) {
                    extraParams = typeof(extraParams) == 'undefined' ? {} : extraParams;

                    return angular.extend(extraParams, $scope.routeParams)
                }
                var generateIdParams = function(row, extraParams) {
                    var params = {};

                    for (var i in $scope.idMap) {
                        var map = $scope.idMap[i];

                        params[i] = $parse(map.substring(4))(row);
                    }

                    return generateParams($.extend(extraParams, params));
                }

                $scope.createPath = function(extraParams) {
                    extraParams = typeof(extraParams) == 'undefined' ? {} : extraParams;
                    return Routing.generate($scope.routes['create'], generateParams(extraParams));
                }
                $scope.editPath = function(row, extraParams) {
                    return Routing.generate($scope.routes['edit'], generateIdParams(row, extraParams));
                }
                $scope.deletePath = function(row, extraParams) {
                    return Routing.generate($scope.routes['delete'], generateIdParams(row, extraParams));
                }

                $scope.getRowTemplate = function(row) {
                    return $scope.editing.indexOf(row) > -1 ? $scope.formTemplate : $scope.bodyTemplate;
                }

                $scope.edit = function(row) {
                    row.$originalData = angular.copy(row);
                    $scope.editing.push(row);
                }
                $scope.create = function() {
                    $scope.newRows.push(self.transform({}));
                }
                $scope.cancel = function(row) {
                    var newRowsIndex = $scope.newRows.indexOf(row);
                    if (newRowsIndex > -1) {
                        $scope.newRows.splice(newRowsIndex, 1);
                        return;
                    }

                    angular.copy(row.$originalData, row);
                    delete row.$originalData;
                    $scope.editing.splice($scope.editing.indexOf(row), 1);
                }

                $scope.$watch('filter', function(newValue) {
                    var result = callDriver('filter', newValue);

                    if (angular.isObject(result) && 'then' in result) {
                        result.then(function() {
                            self.updateData();
                        });

                        return;
                    }

                    self.updateData();
                })

                $scope.$on('row.updated', function(e, row) {
                    $scope.editing.splice($scope.editing.indexOf(row), 1);
                    angular.copy(self.transform(row), row);
                    self.updateData();
//                    self.paginateToObject(row);
                });
                $scope.$on('row.created', function(e, row) {
                    callDriver('addRow', row, self.transform);
                    callDriver('update');
                    $scope.newRows.splice($scope.editing.indexOf(row), 1);
                    self.updateData();
//                    self.paginateToObject(row);
                })

                $scope.$on('row.deleted', function(e, row) {
                    callDriver('deleteRow', row);
                    $scope.editing.splice($scope.editing.indexOf(row), 1);
                    self.updateData();
                })

                $scope.$watch(function() {
                    return getDriver().loading;
                }, function(val) {
                    $scope.loading = val;
                })
            }
        };
        return directiveDefinitionObject;
    }).directive('datagridRow', function() {
        return {
            restrict: 'A',
            require: '^datagrid',
            link: function($scope, iElement, iAttr, datagridCtrl) {
                if (datagridCtrl.getDataService()) {
                    $scope.setDataService(datagridCtrl.getDataService());
                }
            },
            controller: function($scope, $http, $injector) {
                $scope.hasErrors = false;

                var dataService = {};

                $scope.setDataService = function(dataservice) {
                    dataService = $injector.get($scope.dataService);
                }

                $scope.delete = function(row) {
                    if (!confirm('Are you sure you wish to delete this row?')) {
                        return;
                    }

                    $http.delete($scope.deletePath(row, { _format: 'json' }), row).success(function() {
                        $scope.$emit('row.deleted', row);
                    })
                }

                $scope.save = function(row) {
                    var method;
                    var url;

                    if ($scope.isEditable(row)) {
                        method = 'put';
                        url = $scope.editPath(row, { _format: 'json' });
                    } else {
                        method = 'post';
                        url = $scope.createPath({ _format: 'json' });
                    }

                    var options = {};

                    if ('transformRequest' in dataService) {
                        options.transformRequest = dataService.transformRequest;
                    }

                    $http[method](url, row, options).success(function(data) {
                        $scope.$broadcast('errors.updated', {});
                        $scope.hasErrors = false;

                        if (method == 'put') {
                            angular.copy(data, row);
                            $scope.$emit('row.updated', row);
                        } else {
                            if (angular.isArray(data)) {
                                for (var i in data) {
                                    $scope.$emit('row.created', data[i]);
                                }
                            } else {
                                angular.copy(data, row);
                                $scope.$emit('row.created', row);
                            }
                        }
                    }).error(function(data) {
                        if (angular.isObject(data)) {
                            data.errors = data.errors || [];
                            data.errors.unshift('The form has errors');
                        } else {
                            data = { errors: 'An error occurred while saving' };
                        }
                        $scope.hasErrors = true;
                        $scope.$broadcast('errors.updated', data);
                    });
                }
            }
        }
    }).directive('datagridErrors', function() {
        return {
            restrict: 'A',
            require: '^datagridRow',
            scope: true,
            template: '
{{ error }}
',
            link: function($scope, iElement, iAttr, datagrid) {
                $scope.errors = [];
                $scope.path;

                if (iAttr.datagridErrors) {
                    var pathParts = iAttr.datagridErrors.split('.');
                    for (var i = pathParts.length - 1; i >= 0; i--) {
                        pathParts.splice(i, 0, 'children');
                    }
                    $scope.path = pathParts.join('.') + '.errors';
                } else {
                    $scope.path = 'errors';
                }
            },
            controller: function($scope, $parse) {
                $scope.$on('errors.updated', function(e, data) {
                    $scope.errors = $parse($scope.path)(data);
                })
            }
        }
    }).directive('sortable', function() {
        return {
            restrict: 'A',
            require: '^datagrid',
            link: function($scope, iElement, iAttr, datagrid) {
                var name = iAttr.sortable || iAttr.text().toLowerCase();
                iElement.click(function() {
                    $scope.$apply(function() {
                        datagrid.sort(name);
                    })
                });

                $scope.$watch('sort', function(newValue) {
                    if (typeof(newValue) != 'undefined') {
                        iElement.removeClass('sorting sorting_asc sorting_desc');

                        if (name == newValue[0]) {
                            iElement.addClass('sorting_'+newValue[1]);
                        } else {
                            iElement.addClass('sorting');
                        }
                    } else {
                        iElement.addClass('sorting');
                    }
                });
            }
        }
    }).directive('rowClick', function() {
        return {
            restrict: 'A',
            link: function($scope, iElement) {
                iElement.closest('tr')
                    .css('cursor', 'pointer')
                    .on('click', function(e) {
                    if (!$(e.target).is('a') && !($(e.target).closest('a, input').length)) {
                        iElement.click();
                        e.preventDefault();
                    }
                })
            }
        }
    }).directive('datagridFilterbox', function(){
        return {
            restrict: 'E',
            replace: true,
            template: '<input type="text" ng-model="$parent.filter" ng-list="/\\s+/">'
        }
    })
;
<commit_msg>added an event for when the displayed data is changed<commit_after>angular.module('Samson.DataGrid')
    .directive('datagrid', function() {
        var directiveDefinitionObject = {
            restrict: 'E',
            transclude: true,
            scope: 'isolate',
            templateUrl: '/bundles/samsondatagrid/views/datagrid.html',
            replace: true,
            compile: function(tElement, tAttr) {
                if ('ngRowController' in tAttr) {
                    tElement.find('tbody[ng-repeat]').attr('ng-controller', tAttr.ngRowController);
                }

                return function($scope, iElement, iAttr) {
                    var data = null;

                    if ('headerTemplate' in iAttr) {
                        $scope.headerTemplate = iAttr['headerTemplate'];
                    }
                    if ('bodyTemplate' in iAttr) {
                        $scope.bodyTemplate = iAttr['bodyTemplate'];
                    }
                    if ('formTemplate' in iAttr) {
                        $scope.formTemplate = iAttr['formTemplate'];
                    }
                    if ('noResultsTemplate' in iAttr) {
                        $scope.noResultsTemplate = iAttr['noResultsTemplate'];
                    }
                    if ('data' in iAttr) {
                        data = angular.fromJson(iAttr['data']);
                    }
                    if ('filterColumns' in iAttr) {
                        $scope.filterColumns = iAttr.filterColumns.split(',');
                    }
                    if ('service' in iAttr) {
                        $scope.dataService = iAttr.service;
                    }
                    if ('ngRowController' in iAttr) {
                        $scope.rowController = iAttr.ngRowController;
                    }
                    if ('filterTemplate' in iAttr){
                        $scope.filterTemplate = iAttr.filterTemplate;
                    }
                    if ('colgroupTemplate' in iAttr){
                        $scope.colgroupTemplate = iAttr.colgroupTemplate;
                    }
                    $scope.driver = $scope.instantiateDriver('driver' in iAttr ? iAttr['driver'] : 'clientside');

                    if(iAttr.routes) {
                        $scope.routes = $scope.$eval('{'+iAttr.routes+'}');
                    }
                    $scope.routeParams = {};
                    if (iAttr.routeParams) {
                        $scope.routeParams = $scope.$eval(iAttr.routeParams);
                    }
                    $scope.idMap = { id: 'row.id' };
                    if (iAttr.idMap) {
                        $scope.idMap = $scope.$eval(iAttr.idMap);
                    }

                    setTimeout(function() {
                        $scope.$apply(
                            function() {
                                var $headerCells = iElement.find('thead:eq(0) tr:eq(0)').find('th, td');
                                var count = 0;
                                $headerCells.each(function() {
                                    count += parseInt($(this).attr('colspan')) || 1;
                                });

                                $scope.columnCount = count;
                            }

                        );
                    });

                    var loadingEl = null;
                    $scope.$watch('loading', function(val) {
                        if (!val && loadingEl) {
                            setTimeout(function() {
                                loadingEl.width(iElement.find('.table').width()).height(iElement.find('.table').height());
                            }, 0);
                            loadingEl.fadeTo(500, 0, function() {
                                loadingEl.remove();
                                loadingEl = null;
                            })
                        } else if (val && !loadingEl) {
                            loadingEl = $("
").appendTo('body').css({ position: 'absolute', backgroundColor: 'white' }).position({ my: 'left top', at: 'left top', of: iElement.find('.table') })
                                .width(iElement.find('.table').width()).height(iElement.find('.table').height())
                                .fadeTo(0, 0).fadeTo(500, .85);
                        }
                    })

                    $scope.setData(data);
                }
            },
            controller: function($scope, $attrs, $templateCache, $injector, $parse, $q) {
                $scope.editing = [];
                $scope.newRows = [];

                this.getDataService = function() {
                    return $scope.dataService;
                }

                var self = this;
                $scope.headerTemplate = 'datagrid-no-header.html';
                $templateCache.put('datagrid-no-header.html', '
You need to define a header template!
');
                $scope.bodyTemplate = 'datagrid-no-body.html';
                $templateCache.put('datagrid-no-body.html', '
You need to define a body template!
');
                $scope.formTemplate = 'datagrid-no-form.html';
                $templateCache.put('datagrid-no-form.html', '
You need to define a form template!
');
                $scope.noResultsTemplate = 'datagrid-no-results.html';
                $templateCache.put('datagrid-no-results.html', 'No results	');
                $scope.driver = 'clientside';
                $scope.filterTemplate = '/bundles/samsondatagrid/views/filter.html';
                $scope.colgroupTemplate = null;

                $scope.visibleRows = [];

                $scope.$watch('filterColumns', function(newValue) {
                    callDriver('setFilterFields', newValue);
                })

                $scope.instantiateDriver = function(name) {
                    return $injector.instantiate(drivers[name]);
                }

                var getDriver = function() {
                    return $scope.driver;
                }
                var callDriver = function(method) {
                    driver = getDriver();
                    if (!(method in driver)) {
                        throw Error('The driver has no method '+method);
                    }
                    return driver[method].apply(driver, Array.prototype.slice.call(arguments, 1));
                }

                this.transform = function(data) {
                    if (!$scope.dataService) {
                        return data;
                    }

                    var service = $injector.get($scope.dataService);

                    return 'transformResponse' in service ? service.transformResponse(data) : data;
                }

                $scope.setData = function(data) {
                    if (null === data) {
                        service = $injector.get($scope.dataService);
                        if ('getData' in service) {
                            data = service.getData();
                        }
                    }

                    getDriver().loading = true;
                    $q.when(data).then(function(data) {
                        callDriver('setData', data, self.transform);
                        getDriver().loading = false;

                        self.updateData();
                    }, function(reason) {
                        throw Error('Error while fetching data: '+reason);
                    });
                }
                this.updateData = function() {
                    var properties = ['visibleRows', 'firstResult', 'lastResult', 'totalResults', 'filteredResults', 'page', 'pages', 'sort'];
                    for (var i in properties) {
                        var property = properties[i];
                        $scope[property] = callDriver('get'+ property.charAt(0).toUpperCase() + property.slice(1));
                    }

                    $scope.$broadcast('data.updated', callDriver('getVisibleRows'));
                }

                $scope.setPage = function(page) {
                    var result = callDriver('setPage', page);

                    if (angular.isObject(result) && 'then' in result) {
                        result.then(function() {
                            self.updateData();
                        });

                        return;
                    }

                    self.updateData();
                }

                this.sort = function(sortField) {
                    var result = callDriver('sort', sortField);

                    if (angular.isObject(result) && 'then' in result) {
                        result.then(function() {
                            self.updateData();
                        });

                        return;
                    }

                    self.updateData();
                }

                $scope.isEditable = function(row) {
                    return $scope.visibleRows.indexOf(row) > -1;
                }

                var generateParams = function(extraParams) {
                    extraParams = typeof(extraParams) == 'undefined' ? {} : extraParams;

                    return angular.extend(extraParams, $scope.routeParams)
                }
                var generateIdParams = function(row, extraParams) {
                    var params = {};

                    for (var i in $scope.idMap) {
                        var map = $scope.idMap[i];

                        params[i] = $parse(map.substring(4))(row);
                    }

                    return generateParams($.extend(extraParams, params));
                }

                $scope.createPath = function(extraParams) {
                    extraParams = typeof(extraParams) == 'undefined' ? {} : extraParams;
                    return Routing.generate($scope.routes['create'], generateParams(extraParams));
                }
                $scope.editPath = function(row, extraParams) {
                    return Routing.generate($scope.routes['edit'], generateIdParams(row, extraParams));
                }
                $scope.deletePath = function(row, extraParams) {
                    return Routing.generate($scope.routes['delete'], generateIdParams(row, extraParams));
                }

                $scope.getRowTemplate = function(row) {
                    return $scope.editing.indexOf(row) > -1 ? $scope.formTemplate : $scope.bodyTemplate;
                }

                $scope.edit = function(row) {
                    row.$originalData = angular.copy(row);
                    $scope.editing.push(row);
                }
                $scope.create = function() {
                    $scope.newRows.push(self.transform({}));
                }
                $scope.cancel = function(row) {
                    var newRowsIndex = $scope.newRows.indexOf(row);
                    if (newRowsIndex > -1) {
                        $scope.newRows.splice(newRowsIndex, 1);
                        return;
                    }

                    angular.copy(row.$originalData, row);
                    delete row.$originalData;
                    $scope.editing.splice($scope.editing.indexOf(row), 1);
                }

                $scope.$watch('filter', function(newValue) {
                    var result = callDriver('filter', newValue);

                    if (angular.isObject(result) && 'then' in result) {
                        result.then(function() {
                            self.updateData();
                        });

                        return;
                    }

                    self.updateData();
                })

                $scope.$on('row.updated', function(e, row) {
                    $scope.editing.splice($scope.editing.indexOf(row), 1);
                    angular.copy(self.transform(row), row);
                    self.updateData();
//                    self.paginateToObject(row);
                });
                $scope.$on('row.created', function(e, row) {
                    callDriver('addRow', row, self.transform);
                    callDriver('update');
                    $scope.newRows.splice($scope.editing.indexOf(row), 1);
                    self.updateData();
//                    self.paginateToObject(row);
                })

                $scope.$on('row.deleted', function(e, row) {
                    callDriver('deleteRow', row);
                    $scope.editing.splice($scope.editing.indexOf(row), 1);
                    self.updateData();
                })

                $scope.$watch(function() {
                    return getDriver().loading;
                }, function(val) {
                    $scope.loading = val;
                })
            }
        };
        return directiveDefinitionObject;
    }).directive('datagridRow', function() {
        return {
            restrict: 'A',
            require: '^datagrid',
            link: function($scope, iElement, iAttr, datagridCtrl) {
                if (datagridCtrl.getDataService()) {
                    $scope.setDataService(datagridCtrl.getDataService());
                }
            },
            controller: function($scope, $http, $injector) {
                $scope.hasErrors = false;

                var dataService = {};

                $scope.setDataService = function(dataservice) {
                    dataService = $injector.get($scope.dataService);
                }

                $scope.delete = function(row) {
                    if (!confirm('Are you sure you wish to delete this row?')) {
                        return;
                    }

                    $http.delete($scope.deletePath(row, { _format: 'json' }), row).success(function() {
                        $scope.$emit('row.deleted', row);
                    })
                }

                $scope.save = function(row) {
                    var method;
                    var url;

                    if ($scope.isEditable(row)) {
                        method = 'put';
                        url = $scope.editPath(row, { _format: 'json' });
                    } else {
                        method = 'post';
                        url = $scope.createPath({ _format: 'json' });
                    }

                    var options = {};

                    if ('transformRequest' in dataService) {
                        options.transformRequest = dataService.transformRequest;
                    }

                    $http[method](url, row, options).success(function(data) {
                        $scope.$broadcast('errors.updated', {});
                        $scope.hasErrors = false;

                        if (method == 'put') {
                            angular.copy(data, row);
                            $scope.$emit('row.updated', row);
                        } else {
                            if (angular.isArray(data)) {
                                for (var i in data) {
                                    $scope.$emit('row.created', data[i]);
                                }
                            } else {
                                angular.copy(data, row);
                                $scope.$emit('row.created', row);
                            }
                        }
                    }).error(function(data) {
                        if (angular.isObject(data)) {
                            data.errors = data.errors || [];
                            data.errors.unshift('The form has errors');
                        } else {
                            data = { errors: 'An error occurred while saving' };
                        }
                        $scope.hasErrors = true;
                        $scope.$broadcast('errors.updated', data);
                    });
                }
            }
        }
    }).directive('datagridErrors', function() {
        return {
            restrict: 'A',
            require: '^datagridRow',
            scope: true,
            template: '
{{ error }}
',
            link: function($scope, iElement, iAttr, datagrid) {
                $scope.errors = [];
                $scope.path;

                if (iAttr.datagridErrors) {
                    var pathParts = iAttr.datagridErrors.split('.');
                    for (var i = pathParts.length - 1; i >= 0; i--) {
                        pathParts.splice(i, 0, 'children');
                    }
                    $scope.path = pathParts.join('.') + '.errors';
                } else {
                    $scope.path = 'errors';
                }
            },
            controller: function($scope, $parse) {
                $scope.$on('errors.updated', function(e, data) {
                    $scope.errors = $parse($scope.path)(data);
                })
            }
        }
    }).directive('sortable', function() {
        return {
            restrict: 'A',
            require: '^datagrid',
            link: function($scope, iElement, iAttr, datagrid) {
                var name = iAttr.sortable || iAttr.text().toLowerCase();
                iElement.click(function() {
                    $scope.$apply(function() {
                        datagrid.sort(name);
                    })
                });

                $scope.$watch('sort', function(newValue) {
                    if (typeof(newValue) != 'undefined') {
                        iElement.removeClass('sorting sorting_asc sorting_desc');

                        if (name == newValue[0]) {
                            iElement.addClass('sorting_'+newValue[1]);
                        } else {
                            iElement.addClass('sorting');
                        }
                    } else {
                        iElement.addClass('sorting');
                    }
                });
            }
        }
    }).directive('rowClick', function() {
        return {
            restrict: 'A',
            link: function($scope, iElement) {
                iElement.closest('tr')
                    .css('cursor', 'pointer')
                    .on('click', function(e) {
                    if (!$(e.target).is('a') && !($(e.target).closest('a, input').length)) {
                        iElement.click();
                        e.preventDefault();
                    }
                })
            }
        }
    }).directive('datagridFilterbox', function(){
        return {
            restrict: 'E',
            replace: true,
            template: '<input type="text" ng-model="$parent.filter" ng-list="/\\s+/">'
        }
    })
;
<|endoftext|>


<commit_before>function chatController(postId) {
    if (!Notification) {
        console.log('Desktop notifications not available in your browser. Try Chromium.');
    }
    if (localStorage.getItem("desktopNotification") === null) {
        try {
            Notification.requestPermission().then(function (permission) { // denied, granted
                localStorage.setItem("desktopNotification", permission); //TPDO: move to sperate file(LocalStorageDAO)
            });
        } catch (error) {
            // Safari doesn't return a promise for requestPermissions and it
            // throws a TypeError. It takes a callback as the first argument
            // instead.
            if (error instanceof TypeError) {
                Notification.requestPermission(function (permission) {
                    localStorage.setItem("desktopNotification", permission);
                });
            } else {
                // TODO: ignore errors for now test safari
                // throw error;
            }
        }

    }
    var chatDAO = new ChatDAO(postId);
    var lastChatId;
    var firstChatId;
    var isScrollingUp;
    var isWindowActive = true;
    $(window).blur(function () {
        isWindowActive = false;
    });
    $(window).focus(function () {
        isWindowActive = true;
    });
    chatDAO.getChatsInfo({limit: 30}, function (chatsInfo) {
        var members = [];
        var membersMap = {};
        chatsInfo.members.forEach(function (m) {
            var user = new User(m);
            members.push(user);
            membersMap[user.id] = user;
        });

        var chat = new Chat(new User(current_user), members, {}, function (message, callback) {
            myMessageSent = true;
            chatDAO.sendMessage(message, function (error, data) {
                if (callback) {
                    callback(error, data);
                }
            });
        });

        if (chatsInfo.chats.length > 0) {
            lastChatId = chatsInfo.chats[chatsInfo.chats.length - 1].id;
            firstChatId = chatsInfo.chats[0].id; // handle case when no messages.
        }

        chat.setScrollTopEventCallback(function () {
            if (!isScrollingUp) {
                isScrollingUp = true;
                chatDAO.getChatsInfo({before_id: firstChatId, limit: 10}, function (ci) {
                    if (ci.chats.length > 0) {
                        firstChatId = ci.chats[0].id; // move this to a function
                    }
                    var messages = getMessagesFromChatInfo(ci);
                    chat.addMessagesToTop(messages);
                    isScrollingUp = false;
                });
            }
        });
        chat.addMessages(getMessagesFromChatInfo(chatsInfo));
        $('.js_upload_form').on("ajax:remotipartComplete", function (e, data) {
            var c = JSON.parse(data.responseText).chat;
            var msg = new Message(c, membersMap[c.user.id]);
            chat.addMessage(msg);
        });

        setInterval(function () {
            fetchLattestMessages(lastChatId);
        }, 5000);

        function getMessagesFromChatInfo(chatsInfo, excludeMyMessages) {
            var messages = [];
            chatsInfo.chats.forEach(function (chat) {
                if (!(excludeMyMessages && chat.user.id === current_user.id)) {
                    var message = new Message(chat, membersMap[chat.user.id]);
                    messages.push(message);
                } // TODO this will not work if multiple windows are open FIX
            });
            return messages;
        }

        function getUsersFromChatInfo(chatsInfo) {
            var members = [];
            chatsInfo.members.forEach(function (m) {
                var user = new User(m);
                members.push(user);
            });
            return members;
        }

        function fetchLattestMessages() {
            chatDAO.getChatsInfo({after_id: lastChatId}, function (ci) {
                if (ci.chats.length > 0) {
                    lastChatId = ci.chats[ci.chats.length - 1].id; // move this to a function
                }
                var messages = getMessagesFromChatInfo(ci, true);
                chat.addMessages(messages);
                chat.addUsersToUserArea(getUsersFromChatInfo(ci));
                desktopNotification(messages);
            });
        }

    });

    function desktopNotification(messages) {
        if (!isWindowActive && localStorage.getItem("desktopNotification") === "granted") {
            messages.forEach(function (message) {
                var notification = new Notification('New message from ' + message.user.username, {
                    icon: message.user.picture,
                    body: message.text
                    //sound: path //TODO
                });

                notification.onclick = function () {
                    window.focus();
                    //window.open("http://stackoverflow.com/a/13328397/1269037");
                };
            });
        }
    }

}

<commit_msg>ignore notification error<commit_after>function chatController(postId) {
    if (!Notification) {
        console.log('Desktop notifications not available in your browser. Try Chromium.');
    }
    if (localStorage.getItem("desktopNotification") === null) {
        try {
            Notification.requestPermission().then(function (permission) { // denied, granted
                localStorage.setItem("desktopNotification", permission); //TPDO: move to sperate file(LocalStorageDAO)
            });
        } catch (error) {
            // Safari doesn't return a promise for requestPermissions and it
            // throws a TypeError. It takes a callback as the first argument
            // instead.
            if (error instanceof TypeError) {
                try {
                    Notification.requestPermission(function (permission) {
                        localStorage.setItem("desktopNotification", permission);
                    });
                } catch (e) {

                    // ignore
                }

            } else {
                // TODO: ignore errors for now test safari
                // throw error;
            }
        }

    }
    var chatDAO = new ChatDAO(postId);
    var lastChatId;
    var firstChatId;
    var isScrollingUp;
    var isWindowActive = true;
    $(window).blur(function () {
        isWindowActive = false;
    });
    $(window).focus(function () {
        isWindowActive = true;
    });
    chatDAO.getChatsInfo({limit: 30}, function (chatsInfo) {
        var members = [];
        var membersMap = {};
        chatsInfo.members.forEach(function (m) {
            var user = new User(m);
            members.push(user);
            membersMap[user.id] = user;
        });

        var chat = new Chat(new User(current_user), members, {}, function (message, callback) {
            myMessageSent = true;
            chatDAO.sendMessage(message, function (error, data) {
                if (callback) {
                    callback(error, data);
                }
            });
        });

        if (chatsInfo.chats.length > 0) {
            lastChatId = chatsInfo.chats[chatsInfo.chats.length - 1].id;
            firstChatId = chatsInfo.chats[0].id; // handle case when no messages.
        }

        chat.setScrollTopEventCallback(function () {
            if (!isScrollingUp) {
                isScrollingUp = true;
                chatDAO.getChatsInfo({before_id: firstChatId, limit: 10}, function (ci) {
                    if (ci.chats.length > 0) {
                        firstChatId = ci.chats[0].id; // move this to a function
                    }
                    var messages = getMessagesFromChatInfo(ci);
                    chat.addMessagesToTop(messages);
                    isScrollingUp = false;
                });
            }
        });
        chat.addMessages(getMessagesFromChatInfo(chatsInfo));
        $('.js_upload_form').on("ajax:remotipartComplete", function (e, data) {
            var c = JSON.parse(data.responseText).chat;
            var msg = new Message(c, membersMap[c.user.id]);
            chat.addMessage(msg);
        });

        setInterval(function () {
            fetchLattestMessages(lastChatId);
        }, 5000);

        function getMessagesFromChatInfo(chatsInfo, excludeMyMessages) {
            var messages = [];
            chatsInfo.chats.forEach(function (chat) {
                if (!(excludeMyMessages && chat.user.id === current_user.id)) {
                    var message = new Message(chat, membersMap[chat.user.id]);
                    messages.push(message);
                } // TODO this will not work if multiple windows are open FIX
            });
            return messages;
        }

        function getUsersFromChatInfo(chatsInfo) {
            var members = [];
            chatsInfo.members.forEach(function (m) {
                var user = new User(m);
                members.push(user);
            });
            return members;
        }

        function fetchLattestMessages() {
            chatDAO.getChatsInfo({after_id: lastChatId}, function (ci) {
                if (ci.chats.length > 0) {
                    lastChatId = ci.chats[ci.chats.length - 1].id; // move this to a function
                }
                var messages = getMessagesFromChatInfo(ci, true);
                chat.addMessages(messages);
                chat.addUsersToUserArea(getUsersFromChatInfo(ci));
                desktopNotification(messages);
            });
        }

    });

    function desktopNotification(messages) {
        if (!isWindowActive && localStorage.getItem("desktopNotification") === "granted") {
            messages.forEach(function (message) {
                var notification = new Notification('New message from ' + message.user.username, {
                    icon: message.user.picture,
                    body: message.text
                    //sound: path //TODO
                });

                notification.onclick = function () {
                    window.focus();
                    //window.open("http://stackoverflow.com/a/13328397/1269037");
                };
            });
        }
    }

}

<|endoftext|>


<commit_before>//= require ./common
//= require ./ckeditor
//= require bootstrap

! function () {

  var $window = $ (window)

  $.liveQuery.registerPlugin ("html");

  $.fn.modal.defaults = {
        backdrop: 'static'
      , keyboard: true
      , show: true
    }

  $ (document).on ('click', '.redactor_editor', function ()
  {
    var it = $ (this)
    var textarea = it.siblings ('textarea')
    var redactor = textarea.data ('redactor')

    try { redactor.getCurrentNode () }
    catch (ex)
    {
      var range = rangy.createRange();
      range.setStart (this, 0);
      range.collapse (true);
      rangy.getSelection ().setSingleRange (range);
    }
  })

  $.application.debug = true;

  // $('.tab-content').application
  //   (function ($this) { $this.children ().maximise ('height'); });

  $ ('.date.input').application
    (true, function ($this) { $this.koiDatePicker () });

  // $('.rich.text.input').application
  //   (true, function ($this) { $this.koiEditor () });

  $ ('.sortable.fields').application
    (true, function ($this) { $this.koiSortable () });

  $ ('.nested-fields').application
    (true, function ($this) { $this.koiNestedFields () });

  $ ('.superfish').application
    (true, function ($this) { $this.superfish ({ delay:100 }); });

  var fnModal = $.fn.modal

  $.fn.modal = function ()
  {
    var it = $ (this)

    if (it.data ('modal')) return fnModal.apply (this, arguments)

    fnModal.apply (this, arguments)

    if (it.hasClass ('fade')) it.on ('show', function () { it.css ('top', $window.scrollTop () + 100) })
    return this
  }

  $ (document).on ('click', 'a[target=_overlay]', function ()
  {
    var it = $ (this)
    $.modal (it.attr ('href'))
    return false
  })

  $.modal = function (path, ok)
  {
    ok || (ok = function () {})
    var it = this
    var iframe    = $.factory.iframe (path)
    var imodal    = $ ('<div>')
                    .addClass ('asset-manager modal fade in')
                    .html (iframe)
                    .appendTo ('body')
                    .modal ({ backdrop : true })
                    .modal ('show')
    var ibackdrop = imodal.next ('.modal-backdrop')

    iframe.load (function ()
    {
      var iwindow = iframe.contentWindow ()
      var iclose  = iwindow.close
      iwindow.close = function (asset)
      {
        if (asset) ok.call (it, asset)
        imodal.modal ('hide').on ('hidden', function ()
        {
          iclose ()
          imodal.remove ()
          ibackdrop.remove ()
        })
      }
    })
  }

  $ (function ()
  {
    switch (document.location.hash)
    {
      case '#tab-settings': $ ('[href=#tab-settings]').click ()
      case '#tab-extra':    $ ('[href=#tab-extra]').click ()
    }
  })

} (jQuery);
<commit_msg>Fixed wrong tab issue<commit_after>//= require ./common
//= require ./ckeditor
//= require bootstrap

! function () {

  var $window = $ (window)

  $.liveQuery.registerPlugin ("html");

  $.fn.modal.defaults = {
        backdrop: 'static'
      , keyboard: true
      , show: true
    }

  $ (document).on ('click', '.redactor_editor', function ()
  {
    var it = $ (this)
    var textarea = it.siblings ('textarea')
    var redactor = textarea.data ('redactor')

    try { redactor.getCurrentNode () }
    catch (ex)
    {
      var range = rangy.createRange();
      range.setStart (this, 0);
      range.collapse (true);
      rangy.getSelection ().setSingleRange (range);
    }
  })

  $.application.debug = true;

  // $('.tab-content').application
  //   (function ($this) { $this.children ().maximise ('height'); });

  $ ('.date.input').application
    (true, function ($this) { $this.koiDatePicker () });

  // $('.rich.text.input').application
  //   (true, function ($this) { $this.koiEditor () });

  $ ('.sortable.fields').application
    (true, function ($this) { $this.koiSortable () });

  $ ('.nested-fields').application
    (true, function ($this) { $this.koiNestedFields () });

  $ ('.superfish').application
    (true, function ($this) { $this.superfish ({ delay:100 }); });

  var fnModal = $.fn.modal

  $.fn.modal = function ()
  {
    var it = $ (this)

    if (it.data ('modal')) return fnModal.apply (this, arguments)

    fnModal.apply (this, arguments)

    if (it.hasClass ('fade')) it.on ('show', function () { it.css ('top', $window.scrollTop () + 100) })
    return this
  }

  $ (document).on ('click', 'a[target=_overlay]', function ()
  {
    var it = $ (this)
    $.modal (it.attr ('href'))
    return false
  })

  $.modal = function (path, ok)
  {
    ok || (ok = function () {})
    var it = this
    var iframe    = $.factory.iframe (path)
    var imodal    = $ ('<div>')
                    .addClass ('asset-manager modal fade in')
                    .html (iframe)
                    .appendTo ('body')
                    .modal ({ backdrop : true })
                    .modal ('show')
    var ibackdrop = imodal.next ('.modal-backdrop')

    iframe.load (function ()
    {
      var iwindow = iframe.contentWindow ()
      var iclose  = iwindow.close
      iwindow.close = function (asset)
      {
        if (asset) ok.call (it, asset)
        imodal.modal ('hide').on ('hidden', function ()
        {
          iclose ()
          imodal.remove ()
          ibackdrop.remove ()
        })
      }
    })
  }

  $ (function ()
  {
    // FIXME: Needs attention
    if(document.location.hash == '#tab-settings') {
      $ ('[href=#tab-settings]').click ();
    } else if(document.location.hash == '#tab-extra') {
      $ ('[href=#tab-extra]').click ();
    }
  })

} (jQuery);
<|endoftext|>