<commit_before>// include core Park class
const Moment = require('moment-timezone');
const Park = require('../park');
const Location = require('../location');

const sApiBase = Symbol('Asterix Park API Base URL');
const sApiVersion = Symbol('Asterix Park API Version');
const sAppVersion = Symbol('Asterix Park App Version');

const reTime = /(\d+)h - (\d+|Minuit)(?:h?)/ig;
const reHumanTime = /(\d+)h - fermeture à partir de (\d+)h/ig;
const reClosingTime = /(\d+)h(\d+)/;

/**
 * Implements the Asterix Park API
 * @class
 * @extends Park
 */
class AsterixPark extends Park {
  constructor(options = {}) {
    options.name = options.name || 'Parc-Asterix';
    options.timezone = options.timezone || 'Europe/Paris';
    options.latitude = options.latitude || 49.136041;
    options.longitude = options.longitude || 2.572768;

    // inherit from base class
    super(options);

    // API Options
    this[sApiBase] = options.apiBase || 'https://www.parcasterix.fr/webservices/';
    this[sApiVersion] = options.apiVersion || '1';
    this[sAppVersion] = options.appVersion || '320';
  }

  /* eslint-disable class-methods-use-this */
  // this park supports ride schedules
  get SupportsRideSchedules() {
    return true;
  }
  /* eslint-enable class-methods-use-this */

  GetRideData() {
    // cache locally for a week
    return this.Cache.Wrap('ridedata', this.FetchRideData.bind(this), 60 * 60 * 24 * 7);
  }

  FetchRideData() {
    return this.HTTP({
      url: `${this[sApiBase]}api/attractions.json`,
      data: {
        device: 'android',
        version: this[sAppVersion],
        lang: 'fr',
        apiversion: this[sApiVersion],
      },
      mock: 'AsterixRideData',
    }).then((rideResp) => {
      const returnData = {};

      rideResp.result.attractions.forEach((ride) => {
        returnData[ride.code] = {
          name: ride.title,
          location: new Location({
            name: `Asteric Park Ride - ${ride.title}`,
            latitude: ride.latitude,
            longitude: ride.longitude,
            timezone: this.Timezone,
          }),
        };
      });

      return Promise.resolve(returnData);
    });
  }

  FetchWaitTimes() {
    return this.GetRideData().then(rideData => this.HTTP({
      url: `${this[sApiBase]}api/attentix.json`,
      data: {
        device: 'android',
        version: this[sAppVersion],
        lang: 'fr',
        apiversion: this[sApiVersion],
      },
      mock: 'ParcAsterixWaitTimes',
    }).then(waittimes => this.GetOpeningTimes().then((parkTimes) => {
      let allRidesClosed = true;
      let todaysOpeningHour;

      const now = Moment();
      parkTimes.forEach((parkTime) => {
        if (parkTime.type === 'Operating' && now.isBetween(parkTime.openingTime, parkTime.closingTime)) {
          allRidesClosed = false;
          // remember the park's opening hour so we can fill in ride opening times later
          todaysOpeningHour = parkTime.openingTime;
        }
      });

      if (!waittimes.latency || !waittimes.latency.latency) {
        return Promise.reject(new Error("API didn't return expected format"));
      }

      waittimes.latency.latency.forEach((ridetime) => {
        // skip if we haven't got any ride data
        if (!rideData[ridetime.attractionid] || !rideData[ridetime.attractionid].name) {
          return;
        }

        const rideUpdateData = {
          // ride name comes from hard-coded AsterixData.json file
          name: rideData[ridetime.attractionid].name,
          waitTime: -1,
          meta: {},
        };

        // add ride location if available
        if (rideData[ridetime.attractionid] && rideData[ridetime.attractionid].location) {
          rideUpdateData.meta.location = rideData[ridetime.attractionid].location.LocationString;
          rideUpdateData.meta.longitude = rideData[ridetime.attractionid].location.LongitudeRaw || undefined;
          rideUpdateData.meta.latitude = rideData[ridetime.attractionid].location.LatitudeRaw || undefined;
        }

        // if park is closed, just mark all rides as closed
        if (!allRidesClosed) {
          // FYI, latency = "A L'ARRET" / "INDISPONIBLE" / "FERME" / "X" (mn)
          if (ridetime.latency === "A L'ARRET" || ridetime.latency === 'INDISPONIBLE') {
            rideUpdateData.waitTime = -2;
          } else if (ridetime.latency === 'FERME') {
            rideUpdateData.waitTime = -1;
          } else {
            rideUpdateData.waitTime = parseInt(ridetime.latency, 10);

            // add ride opening/closing time meta data (if available)
            if (ridetime.closing_time) {
              const resultRe = reClosingTime.exec(ridetime.closing_time);
              if (resultRe) {
                const closingMoment = Moment.tz(this.Timezone).hours(parseInt(resultRe[1], 10)).minutes(parseInt(resultRe[2], 10)).seconds(0);
                rideUpdateData.meta.rideOpeningTime = todaysOpeningHour;
                rideUpdateData.meta.rideClosingTime = closingMoment.format();
              }
            }
          }
        }

        this.UpdateRide(ridetime.attractionid, rideUpdateData);
      });

      return Promise.resolve();
    })));
  }

  FetchOpeningTimes() {
    return this.HTTP({
      url: `${this[sApiBase]}03/fr`,
      data: {
        device: 'android',
        version: this[sAppVersion],
        lang: 'fr',
        apiversion: this[sApiVersion],
      },
      mock: 'ParcAsterixOpeningHours',
    }).then((openingHours) => {
      if (!openingHours.agenda) {
        return Promise.reject(new Error("API didn't return expected opening hours data"));
      }
      openingHours.agenda.forEach((agenda) => {
        const date = Moment.tz(agenda.jour, 'DD-MM-YYYY', this.Timezone);

        if (agenda.type === 'D') {
          // park is closed
          this.Schedule.SetDate({
            date,
            type: 'Closed',
          });
        } else if (agenda.type === 'A') {
          // A times are weird unspecific times with text
          reHumanTime.lastIndex = 0;
          const match = reHumanTime.exec(agenda.horaire);
          if (match !== null) {
            this.Schedule.SetDate({
              date,
              openingTime: date.clone().hours(parseInt(match[1], 10)).minutes(0).seconds(0),
              closingTime: date.clone().hours(parseInt(match[2], 10)).minutes(0).seconds(0),
              type: 'Operating',
            });
          }
        } else {
          let resultRe;
          let firstResult = true;
          reTime.lastIndex = 0;

          /* eslint-disable no-cond-assign */
          while ((resultRe = reTime.exec(agenda.horaire)) !== null) {
            // - Normal time
            this.Schedule.SetDate({
              date,
              openingTime: date.clone().hours(parseInt(resultRe[1], 10)).minutes(0).seconds(0),
              closingTime: (resultRe[2] === 'Minuit') ? date.endOf('day') : date.clone().hours(parseInt(resultRe[2], 10)).minutes(0).seconds(0),
              // can't send type for "special hours"
              type: !firstResult ? null : 'Operating',
              // first result is normal hours, any further dates are special hours
              specialHours: !firstResult,
            });

            // mark that we've parsed one set of opening hours, assume any others are special
            firstResult = false;
          }
          /* eslint-enable no-cond-assign */
        }
      });

      return Promise.resolve();
    });
  }
}

// export the class
module.exports = AsterixPark;
<commit_msg>[!] Fix for A/C times being used intercahngably and I don't understand the difference<commit_after>// include core Park class
const Moment = require('moment-timezone');
const Park = require('../park');
const Location = require('../location');

const sApiBase = Symbol('Asterix Park API Base URL');
const sApiVersion = Symbol('Asterix Park API Version');
const sAppVersion = Symbol('Asterix Park App Version');

const reTime = /(\d+)h - (\d+|Minuit)(?:h?)/ig;
const reHumanTime = /(\d+)h - fermeture à partir de (\d+)h/ig;
const reClosingTime = /(\d+)h(\d+)/;

/**
 * Implements the Asterix Park API
 * @class
 * @extends Park
 */
class AsterixPark extends Park {
  constructor(options = {}) {
    options.name = options.name || 'Parc-Asterix';
    options.timezone = options.timezone || 'Europe/Paris';
    options.latitude = options.latitude || 49.136041;
    options.longitude = options.longitude || 2.572768;

    // inherit from base class
    super(options);

    // API Options
    this[sApiBase] = options.apiBase || 'https://www.parcasterix.fr/webservices/';
    this[sApiVersion] = options.apiVersion || '1';
    this[sAppVersion] = options.appVersion || '320';
  }

  /* eslint-disable class-methods-use-this */
  // this park supports ride schedules
  get SupportsRideSchedules() {
    return true;
  }
  /* eslint-enable class-methods-use-this */

  GetRideData() {
    // cache locally for a week
    return this.Cache.Wrap('ridedata', this.FetchRideData.bind(this), 60 * 60 * 24 * 7);
  }

  FetchRideData() {
    return this.HTTP({
      url: `${this[sApiBase]}api/attractions.json`,
      data: {
        device: 'android',
        version: this[sAppVersion],
        lang: 'fr',
        apiversion: this[sApiVersion],
      },
      mock: 'ParcAsterixRideData',
    }).then((rideResp) => {
      const returnData = {};

      rideResp.result.attractions.forEach((ride) => {
        returnData[ride.code] = {
          name: ride.title,
          location: new Location({
            name: `Asteric Park Ride - ${ride.title}`,
            latitude: ride.latitude,
            longitude: ride.longitude,
            timezone: this.Timezone,
          }),
        };
      });

      return Promise.resolve(returnData);
    });
  }

  FetchWaitTimes() {
    return this.GetRideData().then(rideData => this.HTTP({
      url: `${this[sApiBase]}api/attentix.json`,
      data: {
        device: 'android',
        version: this[sAppVersion],
        lang: 'fr',
        apiversion: this[sApiVersion],
      },
      mock: 'ParcAsterixWaitTimes',
    }).then(waittimes => this.GetOpeningTimes().then((parkTimes) => {
      let allRidesClosed = true;
      let todaysOpeningHour;

      const now = Moment();
      parkTimes.forEach((parkTime) => {
        if (parkTime.type === 'Operating' && now.isBetween(parkTime.openingTime, parkTime.closingTime)) {
          allRidesClosed = false;
          // remember the park's opening hour so we can fill in ride opening times later
          todaysOpeningHour = parkTime.openingTime;
        }
      });

      if (!waittimes.latency || !waittimes.latency.latency) {
        return Promise.reject(new Error("API didn't return expected format"));
      }

      waittimes.latency.latency.forEach((ridetime) => {
        // skip if we haven't got any ride data
        if (!rideData[ridetime.attractionid] || !rideData[ridetime.attractionid].name) {
          return;
        }

        const rideUpdateData = {
          // ride name comes from hard-coded AsterixData.json file
          name: rideData[ridetime.attractionid].name,
          waitTime: -1,
          meta: {},
        };

        // add ride location if available
        if (rideData[ridetime.attractionid] && rideData[ridetime.attractionid].location) {
          rideUpdateData.meta.location = rideData[ridetime.attractionid].location.LocationString;
          rideUpdateData.meta.longitude = rideData[ridetime.attractionid].location.LongitudeRaw || undefined;
          rideUpdateData.meta.latitude = rideData[ridetime.attractionid].location.LatitudeRaw || undefined;
        }

        // if park is closed, just mark all rides as closed
        if (!allRidesClosed) {
          // FYI, latency = "A L'ARRET" / "INDISPONIBLE" / "FERME" / "X" (mn)
          if (ridetime.latency === "A L'ARRET" || ridetime.latency === 'INDISPONIBLE') {
            rideUpdateData.waitTime = -2;
          } else if (ridetime.latency === 'FERME') {
            rideUpdateData.waitTime = -1;
          } else {
            rideUpdateData.waitTime = parseInt(ridetime.latency, 10);

            // add ride opening/closing time meta data (if available)
            if (ridetime.closing_time) {
              const resultRe = reClosingTime.exec(ridetime.closing_time);
              if (resultRe) {
                const closingMoment = Moment.tz(this.Timezone).hours(parseInt(resultRe[1], 10)).minutes(parseInt(resultRe[2], 10)).seconds(0);
                rideUpdateData.meta.rideOpeningTime = todaysOpeningHour;
                rideUpdateData.meta.rideClosingTime = closingMoment.format();
              }
            }
          }
        }

        this.UpdateRide(ridetime.attractionid, rideUpdateData);
      });

      return Promise.resolve();
    })));
  }

  FetchOpeningTimes() {
    return this.HTTP({
      url: `${this[sApiBase]}03/fr`,
      data: {
        device: 'android',
        version: this[sAppVersion],
        lang: 'fr',
        apiversion: this[sApiVersion],
      },
      mock: 'ParcAsterixOpeningHours',
    }).then((openingHours) => {
      if (!openingHours.agenda) {
        return Promise.reject(new Error("API didn't return expected opening hours data"));
      }
      openingHours.agenda.forEach((agenda) => {
        const date = Moment.tz(agenda.jour, 'DD-MM-YYYY', this.Timezone);

        if (agenda.type === 'D') {
          // park is closed
          this.Schedule.SetDate({
            date,
            type: 'Closed',
          });
        } else {
          // test for weird times with human text
          reHumanTime.lastIndex = 0;
          const match = reHumanTime.exec(agenda.horaire);
          if (match !== null) {
            this.Schedule.SetDate({
              date,
              openingTime: date.clone().hours(parseInt(match[1], 10)).minutes(0).seconds(0),
              closingTime: date.clone().hours(parseInt(match[2], 10)).minutes(0).seconds(0),
              type: 'Operating',
            });
          } else {
            // otherwise parse out simple times
            let resultRe;
            let firstResult = true;
            reTime.lastIndex = 0;

            /* eslint-disable no-cond-assign */
            while ((resultRe = reTime.exec(agenda.horaire)) !== null) {
              // - Normal time
              this.Schedule.SetDate({
                date,
                openingTime: date.clone().hours(parseInt(resultRe[1], 10)).minutes(0).seconds(0),
                closingTime: (resultRe[2] === 'Minuit') ? date.endOf('day') : date.clone().hours(parseInt(resultRe[2], 10)).minutes(0).seconds(0),
                // can't send type for "special hours"
                type: !firstResult ? null : 'Operating',
                // first result is normal hours, any further dates are special hours
                specialHours: !firstResult,
              });

              // mark that we've parsed one set of opening hours, assume any others are special
              firstResult = false;
            }
          }
          /* eslint-enable no-cond-assign */
        }
      });

      return Promise.resolve();
    });
  }
}

// export the class
module.exports = AsterixPark;
<|endoftext|>


<commit_before>const path = require('path');
const express = require('express');
const router = express.Router();

const tokens = process.env.SLACK_TOKENS.split(',');
const commandsPath = path.join(__dirname, 'commands');

router.post(/^(.*)$/, (req, res) => {
  const command = req.params[0];

  // authenticate requests
  if (tokens.indexOf(req.body.token) === -1) {
    return res.status(401).json({ success: false, error: 'Invalid token.'});
  }

  // set channel override
  let channel = '';
  if (req.body.channel_name === 'directmessage' || req.body.channel_name === 'privategroup') {
    channel = req.body.channel_id;
  } else {
    channel = `#${req.body.channel_name}`;
  }
  Object.assign(req, {channel: channel});

  require(commandsPath + command)(req, res);
});

module.exports = router;
<commit_msg>refactor how commands are loaded<commit_after>const fs = require('fs');
const path = require('path');
const express = require('express');
const router = express.Router();

// array of tokens to compare against tokens sent from slack
const tokens = process.env.SLACK_TOKENS.split(',');

// holds the commands that will be matched against route path
const commands = {};
const commandsPath = path.join(__dirname, 'commands');

// synchronously load command modules
fs.readdirSync(commandsPath).forEach((fileName) => {
  const command = path.basename(fileName, path.extname(fileName));
  commands[command] = require(path.join(commandsPath, fileName));
});

router.post(/^(.*)$/, (req, res) => {
  const command = req.params[0].substring(1);

  // authenticate requests
  if (tokens.indexOf(req.body.token) === -1) {
    return res.status(401).json({ success: false, error: 'Invalid token.'});
  }

  // set channel override
  let channel = '';
  if (req.body.channel_name === 'directmessage' || req.body.channel_name === 'privategroup') {
    channel = req.body.channel_id;
  } else {
    channel = `#${req.body.channel_name}`;
  }
  Object.assign(req, {channel: channel});

  // run command
  commands[command](req, res);
});

module.exports = router;
<|endoftext|>


<commit_before>var path = require('path'),
	fs = require('fs'),
	glob = require('glob'),
	_ = require('underscore'),
	_s = require('underscore.string'),
	moment = require('moment'),
	marked = require('marked'),
	lunr = require('lunr'),
	validator = require('validator');

var raneto = {

	// Config array that can be overridden
	config: {
		// The base URL of your site (allows you to use %base_url% in Markdown files)
		base_url: '',
		// The base URL of your images folder (allows you to use %image_url% in Markdown files)
		image_url: '/images',
		// Excerpt length (used in search)
		excerpt_length: 400,
		// The meta value by which to sort pages (value should be an integer)
		// If this option is blank pages will be sorted alphabetically
		page_sort_meta: 'sort',
		// Should categories be sorted numerically (true) or alphabetically (false)
		// If true category folders need to contain a "sort" file with an integer value
		category_sort: true,
		// Specify the path of your content folder where all your '.md' files are located
		content_dir: './content/',
		// Toggle debug logging
		debug: false
	},

	// Regex for page meta
	_metaRegex: /^\/\*([\s\S]*?)\*\//i,

	// Makes filename safe strings
	cleanString: function(str, use_underscore) {
		var u = use_underscore || false;
		str = str.replace(/\//g, ' ').trim();
		if(u){
			return _s.underscored(str);
		} else {
			return _s.trim(_s.dasherize(str), '-');
		}
	},

	// Convert a slug to a title
	slugToTitle: function(slug) {
		slug = slug.replace('.md', '').trim();
		return _s.titleize(_s.humanize(path.basename(slug)));
	},

	// Get meta information from Markdown content
	processMeta: function(markdownContent) {
		var metaArr = markdownContent.match(raneto._metaRegex),
			meta = {};

		var metaString = metaArr ? metaArr[1].trim() : '';
		if(metaString){
			var metas = metaString.match(/(.*): (.*)/ig);
			metas.forEach(function(item){
				var parts = item.split(': ');
				if(parts[0] && parts[1]){
					meta[raneto.cleanString(parts[0], true)] = parts[1].trim();
				}
			});
		}

		return meta;
	},

	// Strip meta from Markdown content
	stripMeta: function(markdownContent) {
		return markdownContent.replace(raneto._metaRegex, '').trim();
	},

	// Replace content variables in Markdown content
	processVars: function(markdownContent) {
		if(typeof raneto.config.base_url !== 'undefined') markdownContent = markdownContent.replace(/\%base_url\%/g, raneto.config.base_url);
		if (typeof raneto.config.image_url !== 'undefined') markdownContent = markdownContent.replace(/\%image_url\%/g, raneto.config.image_url);
		return markdownContent;
	},

	// Get a page
	getPage: function(filePath) {
		try {
			var file = fs.readFileSync(filePath),
				slug = filePath.replace(raneto.config.content_dir, '').trim();

			if(slug.indexOf('index.md') > -1){
				slug = slug.replace('index.md', '');
			}
			slug = slug.replace('.md', '').trim();

			var meta = raneto.processMeta(file.toString('utf-8')),
				content = raneto.stripMeta(file.toString('utf-8'));
			content = raneto.processVars(content);
			var html = marked(content);

			return {
				'slug': slug,
				'title': meta.title ? meta.title : raneto.slugToTitle(slug),
				'body': html,
				'excerpt': _s.prune(_s.stripTags(_s.unescapeHTML(html)), (raneto.config.excerpt_length || 400))
			};
		}
		catch(e){
			if(raneto.config.debug) console.log(e);
			return null;
		}
	},

	// Get a structured array of the contents of contentDir
	getPages: function(activePageSlug) {
		activePageSlug = activePageSlug || '';
		var page_sort_meta = raneto.config.page_sort_meta || '',
			category_sort = raneto.config.category_sort || false,
			files = glob.sync(raneto.config.content_dir +'**/*'),
			filesProcessed = [];

		filesProcessed.push({
			slug: '.',
			title: '',
			is_index: true,
			class: 'category-index',
			sort: 0,
			files: []
		});

		files.forEach(function(filePath){
            var shortPath = filePath.replace(raneto.config.content_dir, '').trim(),
				stat = fs.lstatSync(filePath);

			if(stat.isDirectory()){
				var sort = 0;
				if(category_sort){
					try {
						var sortFile = fs.readFileSync(raneto.config.content_dir + shortPath +'/sort');
						sort = parseInt(sortFile.toString('utf-8'), 10);
					}
					catch(e){
						if(raneto.config.debug) console.log(e);
					}
				}

				filesProcessed.push({
					slug: shortPath,
					title: _s.titleize(_s.humanize(path.basename(shortPath))),
					is_index: false,
					class: 'category-'+ raneto.cleanString(shortPath),
					sort: sort,
					files: []
				});
			}
			if(stat.isFile() && path.extname(shortPath) == '.md'){
				try {
					var file = fs.readFileSync(filePath),
						slug = shortPath,
						pageSort = 0;

					if(shortPath.indexOf('index.md') > -1){
						slug = slug.replace('index.md', '');
					}
					slug = slug.replace('.md', '').trim();

					var dir = path.dirname(shortPath),
						meta = raneto.processMeta(file.toString('utf-8'));

					if(page_sort_meta && meta[page_sort_meta]) pageSort = parseInt(meta[page_sort_meta], 10);

					var val = _.find(filesProcessed, function(item){ return item.slug == dir; });
					val.files.push({
						slug: slug,
						title: meta.title ? meta.title : raneto.slugToTitle(slug),
						active: (activePageSlug.trim() == '/'+ slug),
						sort: pageSort
					});
				}
				catch(e){
					if(raneto.config.debug) console.log(e);
				}
			}
		});

		filesProcessed = _.sortBy(filesProcessed, function(cat){ return cat.sort; });
		filesProcessed.forEach(function(category){
			category.files = _.sortBy(category.files, function(file){ return file.sort; });
		});

		return filesProcessed;
	},

	// Index and search contents
	doSearch: function(query) {
		var files = glob.sync(raneto.config.content_dir +'**/*.md');
		var idx = lunr(function(){
			this.field('title', { boost: 10 });
			this.field('body');
		});

		files.forEach(function(filePath){
			try {
				var shortPath = filePath.replace(raneto.config.content_dir, '').trim(),
					file = fs.readFileSync(filePath);

				var meta = raneto.processMeta(file.toString('utf-8'));
				idx.add({
					'id': shortPath,
					'title': meta.title ? meta.title : raneto.slugToTitle(shortPath),
					'body': file.toString('utf-8')
				});
			}
			catch(e){
				if(raneto.config.debug) console.log(e);
			}
		});

		var results = idx.search(query),
			searchResults = [];
		results.forEach(function(result){
            var page = raneto.getPage(raneto.config.content_dir + result.ref);
            page.excerpt = page.excerpt.replace(new RegExp('('+ query +')', 'gim'), '$1');
            searchResults.push(page);
        });

		return searchResults;
	}

};

module.exports = raneto;
<commit_msg>Add support for ignore directories;<commit_after>var path = require('path'),
	fs = require('fs'),
	glob = require('glob'),
	_ = require('underscore'),
	_s = require('underscore.string'),
	moment = require('moment'),
	marked = require('marked'),
	lunr = require('lunr'),
	validator = require('validator');

var raneto = {

	// Config array that can be overridden
	config: {
		// The base URL of your site (allows you to use %base_url% in Markdown files)
		base_url: '',
		// The base URL of your images folder (allows you to use %image_url% in Markdown files)
		image_url: '/images',
		// Excerpt length (used in search)
		excerpt_length: 400,
		// The meta value by which to sort pages (value should be an integer)
		// If this option is blank pages will be sorted alphabetically
		page_sort_meta: 'sort',
		// Should categories be sorted numerically (true) or alphabetically (false)
		// If true category folders need to contain a "sort" file with an integer value
		category_sort: true,
		// Specify the path of your content folder where all your '.md' files are located
		content_dir: './content/',
		// Toggle debug logging
		debug: false
	},

	// Regex for page meta
	_metaRegex: /^\/\*([\s\S]*?)\*\//i,

	// Makes filename safe strings
	cleanString: function(str, use_underscore) {
		var u = use_underscore || false;
		str = str.replace(/\//g, ' ').trim();
		if(u){
			return _s.underscored(str);
		} else {
			return _s.trim(_s.dasherize(str), '-');
		}
	},

	// Convert a slug to a title
	slugToTitle: function(slug) {
		slug = slug.replace('.md', '').trim();
		return _s.titleize(_s.humanize(path.basename(slug)));
	},

	// Get meta information from Markdown content
	processMeta: function(markdownContent) {
		var metaArr = markdownContent.match(raneto._metaRegex),
			meta = {};

		var metaString = metaArr ? metaArr[1].trim() : '';
		if(metaString){
			var metas = metaString.match(/(.*): (.*)/ig);
			metas.forEach(function(item){
				var parts = item.split(': ');
				if(parts[0] && parts[1]){
					meta[raneto.cleanString(parts[0], true)] = parts[1].trim();
				}
			});
		}

		return meta;
	},

	// Strip meta from Markdown content
	stripMeta: function(markdownContent) {
		return markdownContent.replace(raneto._metaRegex, '').trim();
	},

	// Replace content variables in Markdown content
	processVars: function(markdownContent) {
		if(typeof raneto.config.base_url !== 'undefined') markdownContent = markdownContent.replace(/\%base_url\%/g, raneto.config.base_url);
		if (typeof raneto.config.image_url !== 'undefined') markdownContent = markdownContent.replace(/\%image_url\%/g, raneto.config.image_url);
		return markdownContent;
	},

	// Get a page
	getPage: function(filePath) {
		try {
			var file = fs.readFileSync(filePath),
				slug = filePath.replace(raneto.config.content_dir, '').trim();

			if(slug.indexOf('index.md') > -1){
				slug = slug.replace('index.md', '');
			}
			slug = slug.replace('.md', '').trim();

			var meta = raneto.processMeta(file.toString('utf-8')),
				content = raneto.stripMeta(file.toString('utf-8'));
			content = raneto.processVars(content);
			var html = marked(content);

			return {
				'slug': slug,
				'title': meta.title ? meta.title : raneto.slugToTitle(slug),
				'body': html,
				'excerpt': _s.prune(_s.stripTags(_s.unescapeHTML(html)), (raneto.config.excerpt_length || 400))
			};
		}
		catch(e){
			if(raneto.config.debug) console.log(e);
			return null;
		}
	},

	// Get a structured array of the contents of contentDir
	getPages: function(activePageSlug) {
		activePageSlug = activePageSlug || '';
		var page_sort_meta = raneto.config.page_sort_meta || '',
			category_sort = raneto.config.category_sort || false,
			files = glob.sync(raneto.config.content_dir +'**/*'),
			filesProcessed = [];

		filesProcessed.push({
			slug: '.',
			title: '',
			is_index: true,
			class: 'category-index',
			sort: 0,
			files: []
		});

		files.forEach(function(filePath){
            var shortPath = filePath.replace(raneto.config.content_dir, '').trim(),
				stat = fs.lstatSync(filePath);

			if(stat.isDirectory()){
				var sort = 0;

				//ignore directories that has an ignore file under it
				var ignoreFile = raneto.config.content_dir + shortPath +'/ignore';
				if (fs.existsSync(ignoreFile) && fs.lstatSync(ignoreFile).isFile()) {
					return true;
				}

				if(category_sort){
					try {
						var sortFile = fs.readFileSync(raneto.config.content_dir + shortPath +'/sort');
						sort = parseInt(sortFile.toString('utf-8'), 10);
					}
					catch(e){
						if(raneto.config.debug) console.log(e);
					}
				}

				filesProcessed.push({
					slug: shortPath,
					title: _s.titleize(_s.humanize(path.basename(shortPath))),
					is_index: false,
					class: 'category-'+ raneto.cleanString(shortPath),
					sort: sort,
					files: []
				});
			}
			if(stat.isFile() && path.extname(shortPath) == '.md'){
				try {
					var file = fs.readFileSync(filePath),
						slug = shortPath,
						pageSort = 0;

					if(shortPath.indexOf('index.md') > -1){
						slug = slug.replace('index.md', '');
					}
					slug = slug.replace('.md', '').trim();

					var dir = path.dirname(shortPath),
						meta = raneto.processMeta(file.toString('utf-8'));

					if(page_sort_meta && meta[page_sort_meta]) pageSort = parseInt(meta[page_sort_meta], 10);

					var val = _.find(filesProcessed, function(item){ return item.slug == dir; });
					val.files.push({
						slug: slug,
						title: meta.title ? meta.title : raneto.slugToTitle(slug),
						active: (activePageSlug.trim() == '/'+ slug),
						sort: pageSort
					});
				}
				catch(e){
					if(raneto.config.debug) console.log(e);
				}
			}
		});

		filesProcessed = _.sortBy(filesProcessed, function(cat){ return cat.sort; });
		filesProcessed.forEach(function(category){
			category.files = _.sortBy(category.files, function(file){ return file.sort; });
		});

		return filesProcessed;
	},

	// Index and search contents
	doSearch: function(query) {
		var files = glob.sync(raneto.config.content_dir +'**/*.md');
		var idx = lunr(function(){
			this.field('title', { boost: 10 });
			this.field('body');
		});

		files.forEach(function(filePath){
			try {
				var shortPath = filePath.replace(raneto.config.content_dir, '').trim(),
					file = fs.readFileSync(filePath);

				var meta = raneto.processMeta(file.toString('utf-8'));
				idx.add({
					'id': shortPath,
					'title': meta.title ? meta.title : raneto.slugToTitle(shortPath),
					'body': file.toString('utf-8')
				});
			}
			catch(e){
				if(raneto.config.debug) console.log(e);
			}
		});

		var results = idx.search(query),
			searchResults = [];
		results.forEach(function(result){
            var page = raneto.getPage(raneto.config.content_dir + result.ref);
            page.excerpt = page.excerpt.replace(new RegExp('('+ query +')', 'gim'), '$1');
            searchResults.push(page);
        });

		return searchResults;
	}

};

module.exports = raneto;
<|endoftext|>


<commit_before>/*
 * grunt-php2html
 * https://github.com/bzoerb/grunt-php2html
 *
 * Copyright (c) 2013 Ben Zörb
 * Licensed under the MIT license.
 */
'use strict';

var path = require('path'),
    _ = require('lodash'),
    fs = require('fs'),
    qs = require('qs'),
    shjs = require("shelljs"),
    win32 = process.platform === 'win32';

module.exports = function(grunt) {

    var path = require('path'),
        http = require('http'),
        HTMLHint = require("htmlhint").HTMLHint,
        request = require('request'),
        gateway = require('gateway'),
        compiled = [],
        app, middleware;

    // unlink generated html files
    // usefull if the files get copied and processed later
    grunt.registerMultiTask('php2htmlUnlink', 'Unlink generated HTML', function() {
        grunt.log.ok('removing generated files...');
        compiled.forEach(function(file) {
            fs.unlink(file, function(err) {
                if (err) {
                    grunt.log.warn(err);
                }
            });

        });
    });

    // Please see the Grunt documentation for more information regarding task
    // creation: http://gruntjs.com/creating-tasks
    grunt.registerMultiTask('php2html', 'Generate HTML from PHP', function() {

        var cb = this.async(),
            targetDirectory,
            queryString = '',
            options = this.options({
                processLinks: true,
                process: false,
                htmlhint: undefined,
                docroot: undefined,
                serverPort: 8888
            });

        // nothing to do
        if (this.files.length < 1) {
            grunt.log.warn('Destination not written because no source files were provided.');
            return;
        }

        // read config file for htmlhint if available
        if (options.htmlhintrc) {
            if (options.htmlhintrc === true) {
                options.htmlhintrc = findFile('.htmlhintrc',process.cwd());
            }

            try {
                var rc = grunt.file.readJSON(options.htmlhintrc);
                grunt.util._.defaults(options.htmlhint, rc);
            } catch (err) {
                grunt.log.error('.htmlhintrc not found!');
            }
            delete options.htmlhintrc;
        }

        // set to undefined to use default params when value is true
        if (options.htmlhint === true) {
            options.htmlhint = undefined;
        }

        // set empty object to false to keep backwards compatibility
        if (_.isObject(options.htmlhint) && Object.keys(options.htmlhint).length ===0) {
            options.htmlhint = false;
        }

        // $_GET data
        if (typeof options.getData !== 'undefined') {
            queryString = qs.stringify(options.getData);
        }

        // Loop files array
        grunt.util.async.forEachSeries(this.files, function(f, nextFileObj) {
            // try to get docroot
            // first: docroot from options
            // third: use process cwd
            var docroot = path.normalize(options.docroot || f.orig.cwd || process.cwd());

            // check docroot
            if (!grunt.file.exists(docroot)) {
                grunt.log.warn('Docroot "' + docroot + '" does not exist');
                return nextFileObj();
            }

            // absolutize docroot
            if (!grunt.file.isPathAbsolute(docroot)) {
                docroot = path.normalize(path.join(process.cwd(), docroot));
            }

            // remove trailing slash
            docroot = docroot.replace(/\/$/, '');

            // Warn on and remove invalid source files (if nnull was set).
            var files = f.src.filter(function(filepath) {
                if (!grunt.file.exists(filepath)) {
                    grunt.log.warn('Source file "' + filepath + '" not found.');
                    return false;
                } else {
                    return true;
                }
            });

            // check files
            if (files.length === 0) {
                grunt.log.warn('Destination not written because no source files were found.');

                // No src files, goto next target. Warn would have been issued above.
                return nextFileObj();
            }

            // check if dest is directory
            if (detectDestType(f.dest) === 'directory') {
                targetDirectory = path.normalize(f.dest);
            } else {
                targetDirectory = path.dirname(f.dest);
            }

            // make shure dest directory exists
            if (!grunt.file.isDir(targetDirectory)) {
                grunt.file.mkdir(targetDirectory);
            }

            grunt.util.async.concatSeries(files, function(file, next) {
                var target, uri = computeUri(docroot, file);

                // check if uri exists
                if (!grunt.file.exists(path.join(docroot, uri))) {
                    grunt.log.warn('Source file not found: ', uri);
                    return;
                }

                // compute target filename
                if (detectDestType(f.dest) === 'directory') {
                    target = path.join(targetDirectory, path.basename(uri, '.php') + '.html');
                } else {
                    target = path.join(targetDirectory, path.basename(f.dest));
                }

                grunt.log.debug('----------------------------------');
                grunt.log.debug('docroot: ', docroot);
                grunt.log.debug('uri', uri);
                grunt.log.debug('target', target);
                grunt.log.debug('----------------------------------');

                // start server
                middleware = gateway(docroot, {
                    '.php': 'php-cgi'
                });

                // start server with php middleware
                app = http.createServer(function(req, res) {
                    // Pass the request to gateway middleware
                    middleware(req, res, function(err) {
                        grunt.log.warn(err);
                        res.writeHead(204, err);
                        res.end();
                    });
                });

                grunt.log.write('Processing ' + file + '...');

                compilePhp(options.serverPort, uri, queryString, function(response, err) {

                    // replace relative php links with corresponding html link
                    if (response && options.processLinks) {
                        _.forEach(response.match(/href=['"]([^'"]+\.php(?:\?[^'"]*)?)['"]/gm), function(link) {
                            if (link.match(/:\/\//)) {
                                return;
                            }
                            var hlink = link.replace(/(\w)\.php([^\w])/g, '$1.html$2');
                            response = response.replace(link, hlink);
                        });
                    }

                    // doeas the last part of the job
                    var finish = function(target, response, cb) {
                        var messages = [],
                            empty = typeof response === 'undefined' || response === '';

                        // Lint generated html and check if response is  empty
                        if (options.htmlhint !== false) {
                            console.log(options.htmlhint);
                            messages = HTMLHint.verify(response || '', options.htmlhint);
                        }

                        // move on to the next file if everything went right
                        if (!err && messages.length === 0 && !empty) {
                            grunt.file.write(target, response);
                            grunt.log.ok();
                            grunt.log.debug(target + ' written');
                            compiled.push(target);

                            // there was an error, show messages to the user if applicable and move on
                        } else {
                            grunt.log.error();

                            if (empty) {
                                grunt.log.warn('Resulting HTML is empty');
                            }

                            // output messages
                            messages.forEach(function(message) {
                                grunt.log.writeln("[".red + ( "L" + message.line ).yellow + ":".red + ( "C" + message.col ).yellow + "]".red + ' ' + message.message.yellow);
                                var evidence = message.evidence,
                                    col = message.col;
                                if (col === 0) {
                                    evidence = '?'.inverse.red + evidence;
                                } else if (col > evidence.length) {
                                    evidence = evidence + ' '.inverse.red;
                                } else {
                                    evidence = evidence.slice(0, col - 1) + evidence[col - 1].inverse.red + evidence.slice(col);
                                }

                            });
                        }

                        cb();
                    };

                    // processOutput function
                    if (options.process && typeof options.process === 'function') {
                        options.process(response, function callback(modified) {
                            finish(target, modified, next);
                        });
                    } else {
                        finish(target, response, next);
                    }

                });
            }, function() {
                grunt.log.debug('done');
                nextFileObj();
            });

        }, cb);
    });

    /**
     * Use server with gateway middleware to generate html for the given source
     * @param {int} port
     * @param {string} uri
     * @param {function} callback
     */
    var compilePhp = function(port, uri, query, callback) {
        var url = 'http://localhost:' + port + uri;

        // append query string to url
        if (query) {
            url += '?' + query;
        }

        app.listen(port);

        // start request
        request(url,function(error, response, body) {
            app.close();
            callback(body, error);
        }).end();
    };

    /**
     * Get type of destination path
     * @param {string} dest
     * @returns {string} directory|file
     */
    var detectDestType = function(dest) {
        if (grunt.util._.endsWith(dest, '/') || grunt.util._.endsWith(dest, '\\')) {
            return 'directory';
        } else {
            return 'file';
        }
    };

    /**
     * Compute URI for gateway relative to docroot
     * @param {string} docroot
     * @param {sting} file
     * @returns {string}
     */
    var computeUri = function(docroot, file) {
        var uri;
        // If file ends with a slash apend index file
        if (file[file.length - 1] === '/' || grunt.file.isDir(file)) {
            file = path.join(file, 'index.php');
        }

        // absolutize filepath
        if (!grunt.file.isPathAbsolute(path.dirname(file))) {
            file = path.join(process.cwd(), file);
        }

        if (win32) {
            // use the correct slashes for uri
            uri = file.replace(docroot, '').replace(/[\\]/g, '/');
        } else {
            uri = file.replace(docroot, '');
        }

        // ensure that we have an absolute url
        if (uri.substr(0, 1) !== '/') {
            uri = '/' + uri;
        }

        return uri;
    };

    // Storage for memoized results from find file
    // Should prevent lots of directory traversal &
    // lookups when liniting an entire project
    var findFileResults = {};

    /**
     * Searches for a file with a specified name starting with
     * 'dir' and going all the way up either until it finds the file
     * or hits the root.
     *
     * copied from
     * https://github.com/jshint/jshint/blob/master/src/cli.js
     *
     * @param {string} name filename to search for (e.g. .jshintrc)
     * @param {string} dir  directory to start search from (default:
     *                      current working directory)
     *
     * @returns {string} normalized filename
     */
    function findFile(name, dir) {
        dir = dir || process.cwd();

        var filename = path.normalize(path.join(dir, name));
        if (findFileResults[filename] !== undefined) {
            return findFileResults[filename];
        }

        var parent = path.resolve(dir, "../");

        if (shjs.test("-e", filename)) {
            findFileResults[filename] = filename;
            return filename;
        }

        if (dir === parent) {
            findFileResults[filename] = null;
            return null;
        }

        return findFile(name, parent);
    }

};
<commit_msg>removed debug log<commit_after>/*
 * grunt-php2html
 * https://github.com/bzoerb/grunt-php2html
 *
 * Copyright (c) 2013 Ben Zörb
 * Licensed under the MIT license.
 */
'use strict';

var path = require('path'),
    _ = require('lodash'),
    fs = require('fs'),
    qs = require('qs'),
    shjs = require("shelljs"),
    win32 = process.platform === 'win32';

module.exports = function(grunt) {

    var path = require('path'),
        http = require('http'),
        HTMLHint = require("htmlhint").HTMLHint,
        request = require('request'),
        gateway = require('gateway'),
        compiled = [],
        app, middleware;

    // unlink generated html files
    // usefull if the files get copied and processed later
    grunt.registerMultiTask('php2htmlUnlink', 'Unlink generated HTML', function() {
        grunt.log.ok('removing generated files...');
        compiled.forEach(function(file) {
            fs.unlink(file, function(err) {
                if (err) {
                    grunt.log.warn(err);
                }
            });

        });
    });

    // Please see the Grunt documentation for more information regarding task
    // creation: http://gruntjs.com/creating-tasks
    grunt.registerMultiTask('php2html', 'Generate HTML from PHP', function() {

        var cb = this.async(),
            targetDirectory,
            queryString = '',
            options = this.options({
                processLinks: true,
                process: false,
                htmlhint: undefined,
                docroot: undefined,
                serverPort: 8888
            });

        // nothing to do
        if (this.files.length < 1) {
            grunt.log.warn('Destination not written because no source files were provided.');
            return;
        }

        // read config file for htmlhint if available
        if (options.htmlhintrc) {
            if (options.htmlhintrc === true) {
                options.htmlhintrc = findFile('.htmlhintrc',process.cwd());
            }

            try {
                var rc = grunt.file.readJSON(options.htmlhintrc);
                grunt.util._.defaults(options.htmlhint, rc);
            } catch (err) {
                grunt.log.error('.htmlhintrc not found!');
            }
            delete options.htmlhintrc;
        }

        // set to undefined to use default params when value is true
        if (options.htmlhint === true) {
            options.htmlhint = undefined;
        }

        // set empty object to false to keep backwards compatibility
        if (_.isObject(options.htmlhint) && Object.keys(options.htmlhint).length ===0) {
            options.htmlhint = false;
        }

        // $_GET data
        if (typeof options.getData !== 'undefined') {
            queryString = qs.stringify(options.getData);
        }

        // Loop files array
        grunt.util.async.forEachSeries(this.files, function(f, nextFileObj) {
            // try to get docroot
            // first: docroot from options
            // third: use process cwd
            var docroot = path.normalize(options.docroot || f.orig.cwd || process.cwd());

            // check docroot
            if (!grunt.file.exists(docroot)) {
                grunt.log.warn('Docroot "' + docroot + '" does not exist');
                return nextFileObj();
            }

            // absolutize docroot
            if (!grunt.file.isPathAbsolute(docroot)) {
                docroot = path.normalize(path.join(process.cwd(), docroot));
            }

            // remove trailing slash
            docroot = docroot.replace(/\/$/, '');

            // Warn on and remove invalid source files (if nnull was set).
            var files = f.src.filter(function(filepath) {
                if (!grunt.file.exists(filepath)) {
                    grunt.log.warn('Source file "' + filepath + '" not found.');
                    return false;
                } else {
                    return true;
                }
            });

            // check files
            if (files.length === 0) {
                grunt.log.warn('Destination not written because no source files were found.');

                // No src files, goto next target. Warn would have been issued above.
                return nextFileObj();
            }

            // check if dest is directory
            if (detectDestType(f.dest) === 'directory') {
                targetDirectory = path.normalize(f.dest);
            } else {
                targetDirectory = path.dirname(f.dest);
            }

            // make shure dest directory exists
            if (!grunt.file.isDir(targetDirectory)) {
                grunt.file.mkdir(targetDirectory);
            }

            grunt.util.async.concatSeries(files, function(file, next) {
                var target, uri = computeUri(docroot, file);

                // check if uri exists
                if (!grunt.file.exists(path.join(docroot, uri))) {
                    grunt.log.warn('Source file not found: ', uri);
                    return;
                }

                // compute target filename
                if (detectDestType(f.dest) === 'directory') {
                    target = path.join(targetDirectory, path.basename(uri, '.php') + '.html');
                } else {
                    target = path.join(targetDirectory, path.basename(f.dest));
                }

                grunt.log.debug('----------------------------------');
                grunt.log.debug('docroot: ', docroot);
                grunt.log.debug('uri', uri);
                grunt.log.debug('target', target);
                grunt.log.debug('----------------------------------');

                // start server
                middleware = gateway(docroot, {
                    '.php': 'php-cgi'
                });

                // start server with php middleware
                app = http.createServer(function(req, res) {
                    // Pass the request to gateway middleware
                    middleware(req, res, function(err) {
                        grunt.log.warn(err);
                        res.writeHead(204, err);
                        res.end();
                    });
                });

                grunt.log.write('Processing ' + file + '...');

                compilePhp(options.serverPort, uri, queryString, function(response, err) {

                    // replace relative php links with corresponding html link
                    if (response && options.processLinks) {
                        _.forEach(response.match(/href=['"]([^'"]+\.php(?:\?[^'"]*)?)['"]/gm), function(link) {
                            if (link.match(/:\/\//)) {
                                return;
                            }
                            var hlink = link.replace(/(\w)\.php([^\w])/g, '$1.html$2');
                            response = response.replace(link, hlink);
                        });
                    }

                    // doeas the last part of the job
                    var finish = function(target, response, cb) {
                        var messages = [],
                            empty = typeof response === 'undefined' || response === '';

                        // Lint generated html and check if response is  empty
                        if (options.htmlhint !== false) {
                            messages = HTMLHint.verify(response || '', options.htmlhint);
                        }

                        // move on to the next file if everything went right
                        if (!err && messages.length === 0 && !empty) {
                            grunt.file.write(target, response);
                            grunt.log.ok();
                            grunt.log.debug(target + ' written');
                            compiled.push(target);

                            // there was an error, show messages to the user if applicable and move on
                        } else {
                            grunt.log.error();

                            if (empty) {
                                grunt.log.warn('Resulting HTML is empty');
                            }

                            // output messages
                            messages.forEach(function(message) {
                                grunt.log.writeln("[".red + ( "L" + message.line ).yellow + ":".red + ( "C" + message.col ).yellow + "]".red + ' ' + message.message.yellow);
                                var evidence = message.evidence,
                                    col = message.col;
                                if (col === 0) {
                                    evidence = '?'.inverse.red + evidence;
                                } else if (col > evidence.length) {
                                    evidence = evidence + ' '.inverse.red;
                                } else {
                                    evidence = evidence.slice(0, col - 1) + evidence[col - 1].inverse.red + evidence.slice(col);
                                }

                            });
                        }

                        cb();
                    };

                    // processOutput function
                    if (options.process && typeof options.process === 'function') {
                        options.process(response, function callback(modified) {
                            finish(target, modified, next);
                        });
                    } else {
                        finish(target, response, next);
                    }

                });
            }, function() {
                grunt.log.debug('done');
                nextFileObj();
            });

        }, cb);
    });

    /**
     * Use server with gateway middleware to generate html for the given source
     * @param {int} port
     * @param {string} uri
     * @param {function} callback
     */
    var compilePhp = function(port, uri, query, callback) {
        var url = 'http://localhost:' + port + uri;

        // append query string to url
        if (query) {
            url += '?' + query;
        }

        app.listen(port);

        // start request
        request(url,function(error, response, body) {
            app.close();
            callback(body, error);
        }).end();
    };

    /**
     * Get type of destination path
     * @param {string} dest
     * @returns {string} directory|file
     */
    var detectDestType = function(dest) {
        if (grunt.util._.endsWith(dest, '/') || grunt.util._.endsWith(dest, '\\')) {
            return 'directory';
        } else {
            return 'file';
        }
    };

    /**
     * Compute URI for gateway relative to docroot
     * @param {string} docroot
     * @param {sting} file
     * @returns {string}
     */
    var computeUri = function(docroot, file) {
        var uri;
        // If file ends with a slash apend index file
        if (file[file.length - 1] === '/' || grunt.file.isDir(file)) {
            file = path.join(file, 'index.php');
        }

        // absolutize filepath
        if (!grunt.file.isPathAbsolute(path.dirname(file))) {
            file = path.join(process.cwd(), file);
        }

        if (win32) {
            // use the correct slashes for uri
            uri = file.replace(docroot, '').replace(/[\\]/g, '/');
        } else {
            uri = file.replace(docroot, '');
        }

        // ensure that we have an absolute url
        if (uri.substr(0, 1) !== '/') {
            uri = '/' + uri;
        }

        return uri;
    };

    // Storage for memoized results from find file
    // Should prevent lots of directory traversal &
    // lookups when liniting an entire project
    var findFileResults = {};

    /**
     * Searches for a file with a specified name starting with
     * 'dir' and going all the way up either until it finds the file
     * or hits the root.
     *
     * copied from
     * https://github.com/jshint/jshint/blob/master/src/cli.js
     *
     * @param {string} name filename to search for (e.g. .jshintrc)
     * @param {string} dir  directory to start search from (default:
     *                      current working directory)
     *
     * @returns {string} normalized filename
     */
    function findFile(name, dir) {
        dir = dir || process.cwd();

        var filename = path.normalize(path.join(dir, name));
        if (findFileResults[filename] !== undefined) {
            return findFileResults[filename];
        }

        var parent = path.resolve(dir, "../");

        if (shjs.test("-e", filename)) {
            findFileResults[filename] = filename;
            return filename;
        }

        if (dir === parent) {
            findFileResults[filename] = null;
            return null;
        }

        return findFile(name, parent);
    }

};
<|endoftext|>


<commit_before>/*
 * dependencies: jquery, backbonejs, underscorejs, window.sliMpd.router, window.sliMpd.modules.AbstractView
 */
(function() {
    "use strict";

    var $ = window.jQuery,
        _ = window._;
    window.sliMpd = $.extend(true, window.sliMpd, {
        modules : {}
    });
    window.sliMpd.modules.NavbarView = window.sliMpd.modules.AbstractView.extend({

        rendered : false,

        tabAutocomplete : false,

        searchfield : $('#mainsearch'),

        initialize : function(options) {
            window.sliMpd.modules.AbstractView.prototype.initialize.call(this, options);
        },

        render : function() {
        	// only render page once (to prevent multiple click listeners)
            if (this.rendered) {
                return;
            }

            var that = this;

            $('.ac-ajax-form', this.$el).on('submit', function(e) {
				e.preventDefault();
				var url = window.sliMpd.setGetParameter($(this).attr('action'), 'q', that.searchfield.val());

				// reset form to default action (has been modified by autocomplete)
				$(this).attr("action", $(this).attr("data-defaultaction"));

				window.sliMpd.router.navigate(url, {
					trigger : true
				});

				that.closeAutoComplete();

				// TODO : insert tabbedautocomplete js code
				// TODO : on rendering of search-results, re-init click listener:
				// $('.ui-autocomplete a.ajax-link').off('click', this.genericClickListener).on('click', this.genericClickListener);
			});

			this.tabAutocomplete = that.searchfield.autocomplete({
				source: function( request, response ) {
					NProgress.start();
					$.ajax({
						url: "/autocomplete/all/" + $('#mainsearch').val(),
		          		dataType: "json",
		          		type: 'get',
		          		success: function( data ) {
		          			NProgress.done();
							response( data );
						},
						messages: {
					        noResults: '',
					        results: function() {}
					    }
					});
				},
				sourceCategory: 'all',
				minLength: 3,
				focus: function( event, ui ) {
					$(".ui-helper-hidden-accessible").hide();
					if(typeof ui.item !== 'undefined') {
						ui.item.value = that.stripTags(ui.item.value);
					}
				},
				select: function( event, ui ) {
					// do not navigate away with visible modal
					if(window.sliMpd.modal.$modal.hasClass('in')) {
						return false;
					}
					//console.log(ui.item);
					if(ui.item) {
						$('#searchform').attr('action', ui.item.url);
						$('#searchform').submit();
					}
				}
			}).data("ui-autocomplete");
		     /* custom boostrap markup for items */
			this.tabAutocomplete._renderItem = function (ul, item) {

		     	var widgetLink = '';
		     	if(item.type == 'track') {
		     		widgetLink = $('')
		     			.attr('class', 'trigger-modal')
		     			.attr('href', '/markup/widget-trackcontrol?item='+ item.itemid )
		     			.html(' ')
		     			.bind('click', function(e){
		     				// TODO: find another way to disable autocomplete-select-event when modal-opm has been fired
		     				window.sliMpd.modal.$modal.addClass('in');
		     				e.preventDefault();
		     				// TODO: is it possible to use event listener which already exists on all .trigger-modal elements?
					        $.ajax({
								url: $(this).attr('href')
							}).done(function(response){
								window.sliMpd.modal.renderModalContent(response);
							});
		     			});
		     	}

				var markup = $('
', {'class':'row'})
				.append(
					$('
', {'class':'col-md-2'}).append(
						$('', {'src':item.img, 'width': 50, 'height': 50})
					)
				)
				.append(
					$('
', {'class':'col-md-10'}).append(
						$('', {'href':item.url, html: item.label, 'class': 'ajax-link', 'data-ajaxtarget': '#main'})
						.bind('click', function(e){
							e.preventDefault();
							var $el = $(e.currentTarget);
							window.sliMpd.router.navigate($el.attr('href'), {
								trigger : true
							});
						})
					)
					.append(
						$('
')
					)
					.append(
						$('', {'class': 'dark', text:item.typelabel })
					)
					.append(
						$(widgetLink)
					)
				 );
		         return $("

")
		             .data("item.autocomplete", item)
		             .append(markup)
		             .appendTo(ul);
		     };
		     // create a few filter links in autocomplete widget
			this.tabAutocomplete._renderMenu = function( ul, items, type ) {
				var that = this;
				var markup = $('
').attr('class', 'nav nav-pills ac-nav');
				var filterLinks = ["all", "artist", "album", "label"];
				var cat = this.options.sourceCategory;
				filterLinks.forEach(function(filter){
					$('<button>').attr('type', 'button')
					.attr('class', 'btn btn-primary' + ((cat === filter)?'active':''))
					.attr('data-filter', filter)
					.text(filter).bind('click', function(){
						that.changeAutocompleteUrl(filter);
					}).appendTo(markup);
				});
				$(markup).wrapAll($('
').attr('class', 'ui-state-disabled')).appendTo(ul);

				$.each( items, function( index, item ) {
					that._renderItemData( ul, item );
				});
			};

			// arrow left right for switching between tabs
			that.searchfield.keydown( function( event ) {

				// check if widget is visile
				var isOpen = $( this ).autocomplete( "widget" ).is( ":visible" );

				// TODO: limit functionality on focused item
				//focused = $('#mainsearch').data("ui-autocomplete").menu.element.find("li.ui-state-focus").length;

				if ( isOpen /*&& focused == 1*/ && event.keyCode == $.ui.keyCode.LEFT) {
					var prev = $('.ac-nav button.btn-primaryactive').prev();
					if(prev.length) {
						that.changeAutocompleteUrl(prev.attr('data-filter'));
						return false;
					}
				}

				if ( isOpen /*&& focused == 1*/ && event.keyCode == $.ui.keyCode.RIGHT) {
					var next = $('.ac-nav button.btn-primaryactive').next();
					if(next.length) {
						that.changeAutocompleteUrl(next.attr('data-filter'));
						return false;
					}
				}
			});
            window.sliMpd.modules.AbstractView.prototype.render.call(this);
            this.rendered = true;
       },

       changeAutocompleteUrl : function (type) {
			// set input value to initial searchterm
			this.searchfield.val(this.searchfield.data("ui-autocomplete").term);

			// change ajax-url
			var that = this;
			this.searchfield.autocomplete('option', 'source', function( request, response ) {
				NProgress.start();
				$.ajax({
					url: "/autocomplete/"+ type+"/" + that.searchfield.val(),
		      		dataType: "json",
		      		type: 'get',
		      		success: function( data ) {
		      			NProgress.done();
						response( data );
					},
					messages: {
				        noResults: '',
				        results: function() {}
				    }
				});
			});

			// store active filter in variable
			this.searchfield.autocomplete('option', 'sourceCategory', type);

			// trigger refresh with new ajax-url
			this.searchfield.autocomplete().data("ui-autocomplete")._search();
		},

		stripTags : function ( str ) {
		    str=str.toString();
		    return str.replace(/<\/?[^>]+>/gi, '');
		},

		closeAutoComplete : function() {
			this.searchfield.autocomplete('close');
		}

    });

})();
<commit_msg>hide autocompletewidget after szbmitting searchform<commit_after>/*
 * dependencies: jquery, backbonejs, underscorejs, window.sliMpd.router, window.sliMpd.modules.AbstractView
 */
(function() {
    "use strict";

    var $ = window.jQuery,
        _ = window._;
    window.sliMpd = $.extend(true, window.sliMpd, {
        modules : {}
    });
    window.sliMpd.modules.NavbarView = window.sliMpd.modules.AbstractView.extend({

        rendered : false,

        tabAutocomplete : false,

        searchfield : $('#mainsearch'),

        initialize : function(options) {
            window.sliMpd.modules.AbstractView.prototype.initialize.call(this, options);
        },

        render : function() {
        	// only render page once (to prevent multiple click listeners)
            if (this.rendered) {
                return;
            }

            var that = this;

            $('.ac-ajax-form', this.$el).on('submit', function(e) {
				e.preventDefault();
				var url = window.sliMpd.setGetParameter($(this).attr('action'), 'q', that.searchfield.val());

				// reset form to default action (has been modified by autocomplete)
				$(this).attr("action", $(this).attr("data-defaultaction"));

				// make sure autocomplete does not appear after rendering of resultpage
				that.searchfield.autocomplete( "disable" );

				window.sliMpd.router.navigate(url, {
					trigger : true
				});

				that.enableAutocompleteDelayed();

				// TODO : insert tabbedautocomplete js code
				// TODO : on rendering of search-results, re-init click listener:
				// $('.ui-autocomplete a.ajax-link').off('click', this.genericClickListener).on('click', this.genericClickListener);
			});

			this.tabAutocomplete = that.searchfield.autocomplete({
				source: function( request, response ) {
					NProgress.start();
					$.ajax({
						url: "/autocomplete/all/" + $('#mainsearch').val(),
		          		dataType: "json",
		          		type: 'get',
		          		success: function( data ) {
		          			NProgress.done();
							response( data );
						},
						messages: {
					        noResults: '',
					        results: function() {}
					    }
					});
				},
				sourceCategory: 'all',
				minLength: 3,
				focus: function( event, ui ) {
					$(".ui-helper-hidden-accessible").hide();
					if(typeof ui.item !== 'undefined') {
						ui.item.value = that.stripTags(ui.item.value);
					}
				},
				select: function( event, ui ) {
					// do not navigate away with visible modal
					if(window.sliMpd.modal.$modal.hasClass('in')) {
						return false;
					}
					//console.log(ui.item);
					if(ui.item) {
						$('#searchform').attr('action', ui.item.url);
						$('#searchform').submit();
					}
				}
			}).data("ui-autocomplete");
		     /* custom boostrap markup for items */
			this.tabAutocomplete._renderItem = function (ul, item) {

		     	var widgetLink = '';
		     	if(item.type == 'track') {
		     		widgetLink = $('')
		     			.attr('class', 'trigger-modal')
		     			.attr('href', '/markup/widget-trackcontrol?item='+ item.itemid )
		     			.html(' ')
		     			.bind('click', function(e){
		     				// TODO: find another way to disable autocomplete-select-event when modal-opm has been fired
		     				window.sliMpd.modal.$modal.addClass('in');
		     				e.preventDefault();
		     				// TODO: is it possible to use event listener which already exists on all .trigger-modal elements?
					        $.ajax({
								url: $(this).attr('href')
							}).done(function(response){
								window.sliMpd.modal.renderModalContent(response);
							});
		     			});
		     	}

				var markup = $('
', {'class':'row'})
				.append(
					$('
', {'class':'col-md-2'}).append(
						$('', {'src':item.img, 'width': 50, 'height': 50})
					)
				)
				.append(
					$('
', {'class':'col-md-10'}).append(
						$('', {'href':item.url, html: item.label, 'class': 'ajax-link', 'data-ajaxtarget': '#main'})
						.bind('click', function(e){
							e.preventDefault();
							var $el = $(e.currentTarget);
							window.sliMpd.router.navigate($el.attr('href'), {
								trigger : true
							});
						})
					)
					.append(
						$('
')
					)
					.append(
						$('', {'class': 'dark', text:item.typelabel })
					)
					.append(
						$(widgetLink)
					)
				 );
		         return $("

")
		             .data("item.autocomplete", item)
		             .append(markup)
		             .appendTo(ul);
		     };
		     // create a few filter links in autocomplete widget
			this.tabAutocomplete._renderMenu = function( ul, items, type ) {
				var that = this;
				var markup = $('
').attr('class', 'nav nav-pills ac-nav');
				var filterLinks = ["all", "artist", "album", "label"];
				var cat = this.options.sourceCategory;
				filterLinks.forEach(function(filter){
					$('<button>').attr('type', 'button')
					.attr('class', 'btn btn-primary' + ((cat === filter)?'active':''))
					.attr('data-filter', filter)
					.text(filter).bind('click', function(){
						that.changeAutocompleteUrl(filter);
					}).appendTo(markup);
				});
				$(markup).wrapAll($('
').attr('class', 'ui-state-disabled')).appendTo(ul);

				$.each( items, function( index, item ) {
					that._renderItemData( ul, item );
				});
			};

			// arrow left right for switching between tabs
			that.searchfield.keydown( function( event ) {

				// check if widget is visile
				var isOpen = $( this ).autocomplete( "widget" ).is( ":visible" );

				// TODO: limit functionality on focused item
				//focused = $('#mainsearch').data("ui-autocomplete").menu.element.find("li.ui-state-focus").length;

				if ( isOpen /*&& focused == 1*/ && event.keyCode == $.ui.keyCode.LEFT) {
					var prev = $('.ac-nav button.btn-primaryactive').prev();
					if(prev.length) {
						that.changeAutocompleteUrl(prev.attr('data-filter'));
						return false;
					}
				}

				if ( isOpen /*&& focused == 1*/ && event.keyCode == $.ui.keyCode.RIGHT) {
					var next = $('.ac-nav button.btn-primaryactive').next();
					if(next.length) {
						that.changeAutocompleteUrl(next.attr('data-filter'));
						return false;
					}
				}
			});
            window.sliMpd.modules.AbstractView.prototype.render.call(this);
            this.rendered = true;
       },

       changeAutocompleteUrl : function (type) {
			// set input value to initial searchterm
			this.searchfield.val(this.searchfield.data("ui-autocomplete").term);

			// change ajax-url
			var that = this;
			this.searchfield.autocomplete('option', 'source', function( request, response ) {
				NProgress.start();
				$.ajax({
					url: "/autocomplete/"+ type+"/" + that.searchfield.val(),
		      		dataType: "json",
		      		type: 'get',
		      		success: function( data ) {
		      			NProgress.done();
						response( data );
					},
					messages: {
				        noResults: '',
				        results: function() {}
				    }
				});
			});

			// store active filter in variable
			this.searchfield.autocomplete('option', 'sourceCategory', type);

			// trigger refresh with new ajax-url
			this.searchfield.autocomplete().data("ui-autocomplete")._search();
		},

		stripTags : function ( str ) {
		    str=str.toString();
		    return str.replace(/<\/?[^>]+>/gi, '');
		},

		enableAutocompleteDelayed : function() {
			setTimeout(function(){
				window.sliMpd.navbar.searchfield.autocomplete("enable");
			},
			1000);
		}
    });

})();
<|endoftext|>


<commit_before>const translator = require('../rss/translator/translate.js')

module.exports = function (rssIndex, channel, feed, isTestMessage, callback) {
  var guild = require(`../sources/${channel.guild.id}.json`)
  var rssList = guild.sources
  var attempts = 1

  if (isTestMessage) {
    var successLog = `RSS Test Delivery: (${guild.id}, ${guild.name}) => Sent test message for: ${rssList[rssIndex].link} in channel (${channel.id}, ${channel.name})`;
    //var errLog = `RSS Test Error: Attempt #${attempts} (${guild.id}, ${guild.name}) => channel (${channel.id}, ${channel.name}) => Reason: `;
    var failLog = `RSS Test Delivery Failure: (${guild.id}, ${guild.name}) => channel (${channel.id}, ${channel.name}) for feed ${feed.link}. Reason: `;
  }
  else {
    var successLog = `RSS Delivery: (${guild.id}, ${guild.name}) => Sent message: ${feed.link} in channel (${channel.id}, ${channel.name})`;
    //var errLog = `RSS Delivery Error: Attempt #${attempts} (${guild.id}, ${guild.name}) => channel (${channel.id}, ${channel.name}) => Reason: `;
    var failLog = `RSS Delivery Failure: (${guild.id}, ${guild.name}) => channel (${channel.id}, ${channel.name}) for feed ${feed.link}. Reason: `;
  }

  var message = translator(channel, rssList, rssIndex, feed, isTestMessage)

  if (message) {
    function sendMain () {
      if (message.embedMsg) {
        (function sendCombinedMsg() {
          channel.sendMessage(message.textMsg,message.embedMsg)
          .then(m => {
            // console.log(successLog)
            return callback()
          })
          .catch(err => {
            if (attempts === 4) return callback(failLog + err);
            attempts++
            //console.log(errLog + err)
            setTimeout(sendCombinedMsg, 500)
          });
        })();
      }

      else {
        (function sendTxtMsg() {
          channel.sendMessage(message.textMsg)
          .then(m => {
            // console.log(successLog)
            return callback()
          })
          .catch(err => {
            if (attempts === 4) return callback(failLog + err);
            attempts++
            //console.log(errLog + err)
            setTimeout(sendTxtMsg, 500)
          });
        })();
      }
    }

    if (isTestMessage) {
      (function sendTestDetails() {
        channel.sendMessage(message.testDetails)
        .then(m => {
          sendMain()
          return callback()
        })
        .catch(err => {
          if (attempts === 4) return callback(failLog + err);
          attempts++
          //console.log(errLog + err)
          setTimeout(sendTestDetails, 500)
        });
      })();
    }
    else sendMain();
  }

}
<commit_msg>Fixed init process not ending on filtered msgs<commit_after>const translator = require('../rss/translator/translate.js')

module.exports = function (rssIndex, channel, feed, isTestMessage, callback) {
  var guild = require(`../sources/${channel.guild.id}.json`)
  var rssList = guild.sources
  var attempts = 1

  if (isTestMessage) {
    var successLog = `RSS Test Delivery: (${guild.id}, ${guild.name}) => Sent test message for: ${rssList[rssIndex].link} in channel (${channel.id}, ${channel.name})`;
    //var errLog = `RSS Test Error: Attempt #${attempts} (${guild.id}, ${guild.name}) => channel (${channel.id}, ${channel.name}) => Reason: `;
    var failLog = `RSS Test Delivery Failure: (${guild.id}, ${guild.name}) => channel (${channel.id}, ${channel.name}) for feed ${feed.link}. Reason: `;
  }
  else {
    var successLog = `RSS Delivery: (${guild.id}, ${guild.name}) => Sent message: ${feed.link} in channel (${channel.id}, ${channel.name})`;
    //var errLog = `RSS Delivery Error: Attempt #${attempts} (${guild.id}, ${guild.name}) => channel (${channel.id}, ${channel.name}) => Reason: `;
    var failLog = `RSS Delivery Failure: (${guild.id}, ${guild.name}) => channel (${channel.id}, ${channel.name}) for feed ${feed.link}. Reason: `;
  }

  var message = translator(channel, rssList, rssIndex, feed, isTestMessage)

  if (!message) return callback();

  function sendMain () {
    if (message.embedMsg) {
      (function sendCombinedMsg() {
        channel.sendMessage(message.textMsg,message.embedMsg)
        .then(m => {
          // console.log(successLog)
          return callback()
        })
        .catch(err => {
          if (attempts === 4) return callback(failLog + err);
          attempts++
          //console.log(errLog + err)
          setTimeout(sendCombinedMsg, 500)
        });
      })();
    }

    else {
      (function sendTxtMsg() {
        channel.sendMessage(message.textMsg)
        .then(m => {
          // console.log(successLog)
          return callback()
        })
        .catch(err => {
          if (attempts === 4) return callback(failLog + err);
          attempts++
          //console.log(errLog + err)
          setTimeout(sendTxtMsg, 500)
        });
      })();
    }
  }

  if (isTestMessage) {
    (function sendTestDetails() {
      channel.sendMessage(message.testDetails)
      .then(m => {
        sendMain()
        return callback()
      })
      .catch(err => {
        if (attempts === 4) return callback(failLog + err);
        attempts++
        //console.log(errLog + err)
        setTimeout(sendTestDetails, 500)
      });
    })();
  }
  else sendMain();

}
<|endoftext|>


<commit_before>Package.describe({
  name: 'react-fast-refresh',
  version: '0.1.0',
  summary: 'Automatically update React components with HMR',
  documentation: 'README.md',
  devOnly: true
});

Npm.depends({
  'react-refresh': '0.8.3',
   semver: '7.3.4'
});

Package.onUse(function (api) {
  api.export('ReactFastRefresh');
  api.use('modules');
  api.addFiles('server.js', 'server');
  api.addFiles('client-runtime.js', 'web.browser');
  api.use('hot-module-replacement', { weak: true });
});
<commit_msg>Update react-refresh package<commit_after>Package.describe({
  name: 'react-fast-refresh',
  version: '0.1.0',
  summary: 'Automatically update React components with HMR',
  documentation: 'README.md',
  devOnly: true
});

Npm.depends({
  'react-refresh': '0.9.0',
   semver: '7.3.4'
});

Package.onUse(function (api) {
  api.export('ReactFastRefresh');
  api.use('modules');
  api.addFiles('server.js', 'server');
  api.addFiles('client-runtime.js', 'web.browser');
  api.use('hot-module-replacement', { weak: true });
});
<|endoftext|>


<commit_before>var lineid = 0;
define(
	[
		"modules",
		"dnd"
	],
	function(module, dnd) {
		var SPARQL = function(e) {
			this.e = e;
			this.s_mapping = module.mapping;
		}

		SPARQL.prototype.init = function (name, showName) {
			var that = this;
			var local = $("");
			local.append("
");
			// Add [+]-Button to the content pane
			var input = $("<input class=\"btn\" type=\"button\" value=\"+\">");
			local.append(input);

			var div_rules = $("

");

			input.click(function(e) {
				div_rules.append(that.create());
				info_msg_rules.hide();
				//update("input.click");
			});

			if(showName) {
				var name = $("<input style=\"margin-bottom:0px\" type=\"text\">");
				local.append(" ", name);
			}

			// Create a div, to keep all rules and add it to the content pane
			var info_msg_rules = $(create_info("No " + name +" rules yet. Click the [+] button.", false)); // Empty message
			div_rules.append(info_msg_rules);
			local.append(div_rules);
			this.e.append(local);
			this.spo = local;
			return local;
		}

		SPARQL.prototype.create = function() {

			var that = this;
			var spo_id = "spo" + (lineid++);
			var div_spo = $("

");

			createimg = function() {
				return $("");
			}

			// SPO-divs
			var div_s = $("

"); //  style=\"padding:2px; border: 2px solid red;\"
			var div_p = $("

"); //  style=\"padding:2px; border: 2px solid blue;\"
			var div_o = $("

"); //  style=\"padding:2px; border: 2px solid green;\"

			var map_dnd = function(div) {
				// By dnd.js file
				div.bind('dragstart', dnd.handleDragStart);
				div.bind('dragend', dnd.handleDragEnd);
				div.bind('dragover', dnd.handleDragOver);
				div.bind('drop', dnd.handleDrop);
			}

			map_dnd(div_s);
			map_dnd(div_p);
			map_dnd(div_o);

			var div_del = $("");

			var del_img = $("");
			del_img.click(function() {
				div_spo.remove();
			});
			div_del.append(del_img);

			// Append SPO-divs to main div
			div_spo.append(div_s);
			div_spo.append(div_p);
			div_spo.append(div_o);
			div_spo.append(div_del);

			var s_change = function() {
				var s_text = select_s.find("option:selected").text();

				for(var i = 0; i<that.s_mapping.length; i++) {
					if(that.s_mapping[i][0] == s_text) {
						var p_mapping = that.s_mapping[i][2];

						var p_change = function(e){
							var text = select_p.find("option:selected").text();
							var select_o = null;
							for(var i = 0; i<p_mapping.length; i++) {
								if(p_mapping[i][0] == text) {
									var o_change = function(e){
										//update("o_change");
									};
									var o_mapping = p_mapping[i][2];

									if(typeof(o_mapping) == "undefined") {
										select_o = that.generate_select(div_spo, [["?","?"]], o_change);
									} else {
										select_o = that.generate_select(div_spo, o_mapping, o_change, "actors");
									}
									select_o.blur();
								}
							}
							div_o.empty();
							div_o.append(select_o);
							//update("p_change");
						};
						var select_p = that.generate_select(div_spo, p_mapping, p_change, "actors");
						div_p.empty();
						div_p.append(select_p);

						// Empty select for O
						var select_o = $('<select class="o"></select>');
						select_o.append("<option value=\"?\">?</option>");

						select_p.trigger('change');
					}
				}
				//update("s_change");
			}

			// Select for S
			var select_s = this.generate_select(div_spo, this.s_mapping, s_change, "actors");
			div_s.append(select_s);
			select_s.trigger('change');
			return div_spo;
		}

		// o[0] what to show
		// o[1] what to map
		// o[2]
		// o[3] preselected
		// event changeevent
		SPARQL.prototype.generate_select = function (div_spo, o, event, str) {
			var select = $('<select></select>');
			var that = this;
			var isOpened = false;
			var handle = function(o,str) {
				for(var j = 0; j<o.length; j++) {
					var option = "<option value=\"" + o[j][1] + "\" ";

					if(typeof(str) == "string" && typeof(o[j][2]) == "string") {
						option += "" + str + "=\"" + o[j][2] + "\" ";
					}

					if(o[j][3] == true) {
						option += " selected";
					}
					option += ">" + o[j][0] + "</option>";
					select.append(option);
				}
			}

			if(isArray(o)) {
				handle(o,str);
			} else {
				// Default value for the SELECT
				handle(o.data, str);
				var onClick = function(o, div_spo, that) {
					return function() {
						//isOpened = !isOpened;
						//if(isOpened) {
							select.find("option:gt(0)").remove();
							o.handler(handle, div_spo, that);
						//}
					}
				}
				select.focusin(onClick(o, div_spo, that))
			}

			if(typeof(event) == "function") {
				select.change(event);
			}
			return select;
		}

		SPARQL.prototype.getSparql = function (spo) {

			if(typeof spo === "undefined") {
				spo = this.spo.find(".query-spo");
			}

			var valCnt = 0;
			var q = null;
			var result = new Object();
			if(spo.length == 0) {
				return;
			} else {

				var ids = [];

				q = "";
				var actors = [];
				var variables = [];
				for(var i = 0; i < spo.length; i++) {
					var children = spo[i].childNodes;

		            var tmp = "";

					for(var j = 0; j < children.length; j++) {
						var c = children[j];
						var v = $(c).attr("data-var");
						var e = $(c.firstChild);
						// Skip the dnd-image
						if(e.is("img")) break;
						var option = e.find("option:selected");
						var actor = option.attr("actors");
						if(typeof(actor) == "string" && actor != "") {
							actors.push(actor);
						}

						var val = e.val();
						if(val.startsWith("[") && val.endsWith("]")) {
							val = "<" + val.substring(1,val.length-1) + ">";
						}
						var cont = false;

						if(typeof(v) == "string" && val.indexOf("{val}") >= 0) {
							if(val.indexOf("{val}") >= 0) {
								val = val.replace(new RegExp("{val}", "g"), "?" + v);
							}
		                    tmp += val;
						} else if (val == "?") {
							var varx = "?val" + (++valCnt);
							variables.push(varx);
							tmp += varx;
						} else if (typeof(v) != "string" && val.indexOf("{val}") >= 0) {
							var varx = "?val" + (++valCnt);
							variables.push(varx);
							if(val.indexOf("{val}") >= 0) {
								val = val.replace(new RegExp("{val}", "g"), varx);
							}
		                    tmp += val;
						} else {
		                    tmp += val;
						}

						tmp += " ";
					}

		            // http://coding.pressbin.com/16/Javascript-equivalent-of-PHPs-pregmatchall
		            function preg_match_all(regex, haystack) {
		                var globalRegex = new RegExp(regex, 'g');
		                var globalMatch = haystack.match(globalRegex);
		                matchArray = new Array();
						if(globalMatch != null) {
			                for(var gmi = 0; gmi < globalMatch.length; gmi++) {
			                    nonGlobalRegex = new RegExp(regex);
			                    nonGlobalMatch = globalMatch[gmi].match(nonGlobalRegex);
			                    matchArray.push(nonGlobalMatch[1]);
			                }
						}
		                return matchArray;
		            }

		            var regex = '{([^"]*?)}';
		            var matches = preg_match_all(regex, tmp);

		            // http://stackoverflow.com/a/15868720/605890
		            var uniq = matches.reduce(function(a,b){
		                if (a.indexOf(b) < 0 ) a.push(b);
		                return a;
		            },[]);

		            // Replace the vars
		            for(var k = 0; k<uniq.length; k++) {
		                var varname = uniq[k];
		                var varx = "?" + varname + (++valCnt);
						variables.push(varx);
		                tmp = tmp.replace(new RegExp("{" + varname + "}", "g"), varx);

		                // Check, if any actor is a variable as well
		                if(actors.length > 0) {
		                    for(var aidx = 0; aidx < actors.length; aidx++) {
		                        var actor = actors[aidx];
		                        if(actor == "{" + varname + "}") {
		                            actors[aidx] = varx;
		                        }
		                    }
		                }
		            }

		            // Here, one line is complete
		            if(tmp.indexOf("<s>") >= 0) {
		                var varx = "?val" + (++valCnt);
						variables.push(varx);
		                tmp = tmp.replace(new RegExp("<s>", "g"), "" + varx + " ");
		            }

		            q += "\t" + tmp + " . \n";
				}

		        q = q.replace(new RegExp("lightThreshold!", "g"), config.get("lightThreshold"));

				//q = "{\n" + q + "}";

				if(actors.length == 0) {
					result.selections = "*";
					result.hasActuator = false;
					console.log("Query does not contain any actor!");
				} else {
					result.hasActuator = true;
					result.selections = actors.join(" ");
				}

				result.variables = variables;
				result.query = q;
				//console.log(q);
			}

			result.prefixes = "";
			for(var i = 0; i<module.prefixes.length; i++) {
				result.prefixes += "PREFIX " + module.prefixes[i][0] + ":<" + module.prefixes[i][1] + ">\n";
			}
			result.sparql = result.prefixes + "\n" + "SELECT DISTINCT " + implode(" ", result.selections) + " WHERE {\n " + result.query + "}\n";
			return result;
		}

		return SPARQL;
	}
)

<commit_msg>Work on asynchronious loading<commit_after>var lineid = 0;
define(
	[
		"modules",
		"dnd"
	],
	function(module, dnd) {
		var SPARQL = function(e) {
			this.e = e;
			this.s_mapping = module.mapping;
		}

		SPARQL.prototype.init = function (name, showName) {
			var that = this;
			var local = $("");
			local.append("
");
			// Add [+]-Button to the content pane
			var input = $("<input class=\"btn\" type=\"button\" value=\"+\">");
			local.append(input);

			var div_rules = $("

");

			input.click(function(e) {
				div_rules.append(that.create());
				info_msg_rules.hide();
				//update("input.click");
				//console.log("INPUT CLICKED!");
			});

			if(showName) {
				var name = $("<input style=\"margin-bottom:0px\" type=\"text\">");
				local.append(" ", name);
			}

			// Create a div, to keep all rules and add it to the content pane
			var info_msg_rules = $(create_info("No " + name +" rules yet. Click the [+] button.", false)); // Empty message
			div_rules.append(info_msg_rules);
			local.append(div_rules);
			this.e.append(local);
			this.spo = local;
			return local;
		}

		SPARQL.prototype.create = function() {

			var that = this;
			var spo_id = "spo" + (lineid++);
			var div_spo = $("

");

			createimg = function() {
				return $("");
			}

			// SPO-divs
			var div_s = $("

"); //  style=\"padding:2px; border: 2px solid red;\"
			var div_p = $("

"); //  style=\"padding:2px; border: 2px solid blue;\"
			var div_o = $("

"); //  style=\"padding:2px; border: 2px solid green;\"

			var map_dnd = function(div) {
				// By dnd.js file
				div.bind('dragstart', dnd.handleDragStart);
				div.bind('dragend', dnd.handleDragEnd);
				div.bind('dragover', dnd.handleDragOver);
				div.bind('drop', dnd.handleDrop);
			}

			map_dnd(div_s);
			map_dnd(div_p);
			map_dnd(div_o);

			var div_del = $("");

			var del_img = $("");
			del_img.click(function() {
				div_spo.remove();
			});
			div_del.append(del_img);

			// Append SPO-divs to main div
			div_spo.append(div_s);
			div_spo.append(div_p);
			div_spo.append(div_o);
			div_spo.append(div_del);

			var s_change = function() {
				var s_text = select_s.find("option:selected").text();

				for(var i = 0; i<that.s_mapping.length; i++) {
					if(that.s_mapping[i][0] == s_text) {
						var p_mapping = that.s_mapping[i][2];

						var p_change = function(e){
							var text = select_p.find("option:selected").text();
							var select_o = null;
							for(var i = 0; i<p_mapping.length; i++) {
								if(p_mapping[i][0] == text) {
									var o_change = function(e){
										//update("o_change");
									};
									var o_mapping = p_mapping[i][2];

									if(typeof(o_mapping) == "undefined") {
										select_o = that.generate_select(div_spo, [["?","?"]], o_change);
									} else {
										select_o = that.generate_select(div_spo, o_mapping, o_change, "actors");
									}
									select_o.blur();
								}
							}
							div_o.empty();
							div_o.append(select_o);
							//update("p_change");
						};
						var select_p = that.generate_select(div_spo, p_mapping, p_change, "actors");
						div_p.empty();
						div_p.append(select_p);

						// Empty select for O
						var select_o = $('<select class="o"></select>');
						select_o.append("<option value=\"?\">?</option>");

						select_p.trigger('change');
					}
				}
				//update("s_change");
			}

			// Select for S
			var select_s = this.generate_select(div_spo, this.s_mapping, s_change, "actors");
			div_s.append(select_s);
			select_s.trigger('change');
			return div_spo;
		}

		// o[0] what to show
		// o[1] what to map
		// o[2]
		// o[3] preselected
		// event changeevent
		SPARQL.prototype.generate_select = function (div_spo, o, event, str) {
			var select = $('<select></select>');
			var that = this;
			var isOpened = false;
			var handle = function(o,str) {
				for(var j = 0; j<o.length; j++) {
					var option = "<option value=\"" + o[j][1] + "\" ";

					if(typeof(str) == "string" && typeof(o[j][2]) == "string") {
						option += "" + str + "=\"" + o[j][2] + "\" ";
					}

					if(o[j][3] == true) {
						option += " selected";
					}
					option += ">" + o[j][0] + "</option>";
					select.append(option);
				}
			}

			if(isArray(o)) {
				handle(o,str);
			} else {
				// Default value for the SELECT
				handle(o.data, str);
				var onClick = function(o, div_spo, that) {
					// Reload the data
					return function() {
						isOpened = !isOpened;
						if(isOpened) {
							console.log("Load data!");
							select.find("option:gt(0)").remove();
							o.handler(handle, div_spo, that);
						}
					}
				}
				select.focusin(onClick(o, div_spo, that));

				/*
				var selected = false;
				select.mousedown( function(){ console.log( 'down' ); selected = $( this ).val() } )
		  			.blur( function(){ console.log( 'out' ) } )
		  			.change( function(){ console.log( 'out' ) } )
		  			.mouseleave( function(){ console.log( 'out' ) } )
		  			.mouseup( function(){
		    			if( $( this ).val() == selected ) {
		       				console.log( 'out' )
						}
					});
				*/
			}

			if(typeof(event) == "function") {
				select.change(event);
			}
			return select;
		}

		SPARQL.prototype.getSparql = function (spo) {

			if(typeof spo === "undefined") {
				spo = this.spo.find(".query-spo");
			}

			var valCnt = 0;
			var q = null;
			var result = new Object();
			if(spo.length == 0) {
				return;
			} else {

				var ids = [];

				q = "";
				var actors = [];
				var variables = [];
				for(var i = 0; i < spo.length; i++) {
					var children = spo[i].childNodes;

		            var tmp = "";

					for(var j = 0; j < children.length; j++) {
						var c = children[j];
						var v = $(c).attr("data-var");
						var e = $(c.firstChild);
						// Skip the dnd-image
						if(e.is("img")) break;
						var option = e.find("option:selected");
						var actor = option.attr("actors");
						if(typeof(actor) == "string" && actor != "") {
							actors.push(actor);
						}

						var val = e.val();
						if(val.startsWith("[") && val.endsWith("]")) {
							val = "<" + val.substring(1,val.length-1) + ">";
						}
						var cont = false;

						if(typeof(v) == "string" && val.indexOf("{val}") >= 0) {
							if(val.indexOf("{val}") >= 0) {
								val = val.replace(new RegExp("{val}", "g"), "?" + v);
							}
		                    tmp += val;
						} else if (val == "?") {
							var varx = "?val" + (++valCnt);
							variables.push(varx);
							tmp += varx;
						} else if (typeof(v) != "string" && val.indexOf("{val}") >= 0) {
							var varx = "?val" + (++valCnt);
							variables.push(varx);
							if(val.indexOf("{val}") >= 0) {
								val = val.replace(new RegExp("{val}", "g"), varx);
							}
		                    tmp += val;
						} else {
		                    tmp += val;
						}

						tmp += " ";
					}

		            // http://coding.pressbin.com/16/Javascript-equivalent-of-PHPs-pregmatchall
		            function preg_match_all(regex, haystack) {
		                var globalRegex = new RegExp(regex, 'g');
		                var globalMatch = haystack.match(globalRegex);
		                matchArray = new Array();
						if(globalMatch != null) {
			                for(var gmi = 0; gmi < globalMatch.length; gmi++) {
			                    nonGlobalRegex = new RegExp(regex);
			                    nonGlobalMatch = globalMatch[gmi].match(nonGlobalRegex);
			                    matchArray.push(nonGlobalMatch[1]);
			                }
						}
		                return matchArray;
		            }

		            var regex = '{([^"]*?)}';
		            var matches = preg_match_all(regex, tmp);

		            // http://stackoverflow.com/a/15868720/605890
		            var uniq = matches.reduce(function(a,b){
		                if (a.indexOf(b) < 0 ) a.push(b);
		                return a;
		            },[]);

		            // Replace the vars
		            for(var k = 0; k<uniq.length; k++) {
		                var varname = uniq[k];
		                var varx = "?" + varname + (++valCnt);
						variables.push(varx);
		                tmp = tmp.replace(new RegExp("{" + varname + "}", "g"), varx);

		                // Check, if any actor is a variable as well
		                if(actors.length > 0) {
		                    for(var aidx = 0; aidx < actors.length; aidx++) {
		                        var actor = actors[aidx];
		                        if(actor == "{" + varname + "}") {
		                            actors[aidx] = varx;
		                        }
		                    }
		                }
		            }

		            // Here, one line is complete
		            if(tmp.indexOf("<s>") >= 0) {
		                var varx = "?val" + (++valCnt);
						variables.push(varx);
		                tmp = tmp.replace(new RegExp("<s>", "g"), "" + varx + " ");
		            }

		            q += "\t" + tmp + " . \n";
				}

		        q = q.replace(new RegExp("lightThreshold!", "g"), config.get("lightThreshold"));

				//q = "{\n" + q + "}";

				if(actors.length == 0) {
					result.selections = "*";
					result.hasActuator = false;
					console.log("Query does not contain any actor!");
				} else {
					result.hasActuator = true;
					result.selections = actors.join(" ");
				}

				result.variables = variables;
				result.query = q;
				//console.log(q);
			}

			result.prefixes = "";
			for(var i = 0; i<module.prefixes.length; i++) {
				result.prefixes += "PREFIX " + module.prefixes[i][0] + ":<" + module.prefixes[i][1] + ">\n";
			}
			result.sparql = result.prefixes + "\n" + "SELECT DISTINCT " + implode(" ", result.selections) + " WHERE {\n " + result.query + "}\n";
			return result;
		}

		return SPARQL;
	}
)

<|endoftext|>