<commit_before>import { startSubmit, stopSubmit, reset } from 'redux-form';
import _ from 'lodash'
import { hashHistory } from 'react-router';
import i18next from 'i18next'
import { LOAD, ADD_MODULE } from './actionTypes'
import { loadAbiByName, getContract, blockchain, getTransaction, createModule, createModuleWatch, getModuleAddress } from '../../utils/web3'
import { promiseFor } from '../../utils/helper'
import { flashMessage } from '../app/actions'
import { loadModule as aclLoadModule } from '../acl/actions'
// import { loadModule as tokenLoadModule } from '../token/actions'
// import { loadModule as tokenAclLoadModule } from '../tokenAcl/actions'
// import { loadModule as ambixLoadModule } from '../ambix/actions'
// import { loadModule as marketLoadModule } from '../market/actions'

export function observeModules() {
  const loadModule = {
    acl: aclLoadModule,
    // token: tokenLoadModule,
    // 'token-acl': tokenAclLoadModule,
    // ambix: ambixLoadModule,
    // market: marketLoadModule
  }
  return (dispatch, getState) => {
    blockchain.setSubscribe((bl) => {
      _.forEach(bl.transactions, (txId) => {
        const info = getTransaction(txId);
        const state = getState()
        _.forEach(state.dao.blocks, (block) => {
          _.forEach(block.modules, (module) => {
            if (module.address === info.from || module.address === info.to) {
              dispatch(loadModule[block.type](module.address))
            }
          })
        })
      })
    })
  }
}

export function addModule(type, name, address) {
  return {
    type: ADD_MODULE,
    payload: {
      type,
      name,
      address
    }
  }
}

export function load(daoAddress) {
  return (dispatch) => {
    loadAbiByName('Core')
      .then((abi) => {
        const core = getContract(abi, daoAddress);
        const blocks = [
          {
            name: i18next.t('dao:groupAuditors'),
            type: 'acl',
            modules: []
          },
          {
            name: i18next.t('dao:holder'),
            type: 'holder',
            modules: []
          },
          {
            name: i18next.t('dao:auditor'),
            type: 'auditor',
            modules: []
          },
          {
            name: i18next.t('dao:complier'),
            type: 'complier',
            modules: []
          },
          {
            name: i18next.t('dao:token'),
            type: 'token',
            modules: []
          },
          {
            name: i18next.t('dao:carbonRegistry'),
            type: 'token-acl',
            modules: []
          },
          // {
          //   name: i18next.t('dao:market'),
          //   type: 'market',
          //   modules: []
          // }
        ]
        core.call('first')
          .then(firstAddress => (
            promiseFor(address => address !== '0x0000000000000000000000000000000000000000', (address) => {
              core.call('abiOf', [address])
                .then((type) => {
                  if (type === 'tokenAcl') {
                    return 'token-acl'
                  }
                  return type
                })
                .then((type) => {
                  const block = _.find(blocks, ['type', type])
                  if (block) {
                    core.call('getName', [address])
                      .then((name) => {
                        block.modules.push({
                          name,
                          address
                        })
                      })
                  }
                })
              return core.call('next', [address])
            }, firstAddress)
          ))
          .then(() => core.call('name'))
          .then((name) => {
            dispatch({
              type: LOAD,
              payload: {
                address: daoAddress,
                name,
                blocks
              }
            })
          });
        // dispatch(observeModules())
      })
  }
}

export function create(dispatch, module, values) {
  let builderAddress
  let builder
  return getModuleAddress(module)
    .then((address) => {
      builderAddress = address;
      return loadAbiByName(module)
    })
    .then((abi) => {
      builder = getContract(abi, builderAddress)
      return createModule(builder, values)
    })
    .then((txId) => {
      dispatch(flashMessage('txId: ' + txId))
      return createModuleWatch(builder)
    })
}

export function setModule(dispatch, daoAddress, name, address, type) {
  return loadAbiByName('Core')
    .then((abi) => {
      const core = getContract(abi, daoAddress);
      return core.send('setModule', [name, address, type, false])
    })
    .then((txId) => {
      dispatch(flashMessage('txId: ' + txId))
      return blockchain.subscribeTx(txId)
    })
    .then(transaction => transaction.blockNumber)
}

export function submitCreateModule(form, action) {
  return (dispatch) => {
    let builder = false;
    switch (action) {
      case 'core':
        builder = 'BuilderOperator'
        break;
      case 'issuer':
        builder = 'BuilderIssuerLedger'
        break;
      case 'auditor':
        builder = 'BuilderAuditor'
        break;
      case 'complier':
        builder = 'BuilderComplier'
        break;
      case 'market':
        builder = 'BuilderMarket'
        break;
      case 'token':
        builder = 'BuilderTokenEmission'
        break;
      case 'tokenAcl':
        builder = 'BuilderTokenEmissionACL'
        break;
      case 'acl':
        builder = 'BuilderACLStorage'
        break;
      default:
        break;
    }
    if (builder) {
      dispatch(startSubmit('FormCreator'));
      create(dispatch, builder, _.values(form))
        .then((address) => {
          dispatch(stopSubmit('FormCreator'))
          dispatch(reset('FormCreator'))
          dispatch(flashMessage('address: ' + address))
          if (action !== 'core' && action !== 'issuer' && action !== 'auditor' && action !== 'complier') {
            hashHistory.push('/dao/link/' + action + '/' + address)
          }
        })
        .catch((e) => {
          console.log(e);
          dispatch(stopSubmit('FormCreator'))
        })
    }
  }
}

export function submitLinkModule(daoAddress, form) {
  return (dispatch) => {
    dispatch(startSubmit('FormLinkModule'));
    setModule(dispatch, daoAddress, form.name, form.address, form.type)
      .then((blockNumber) => {
        dispatch(stopSubmit('FormLinkModule'))
        dispatch(reset('FormLinkModule'))
        dispatch(flashMessage('blockNumber: ' + blockNumber))
        dispatch(addModule(form.type, form.name, form.address))
      })
      .catch(() => {
        dispatch(stopSubmit('FormLinkModule'))
      })
  }
}

function run(dispatch, address, abiName, action, values) {
  return loadAbiByName(abiName)
    .then((abi) => {
      const contract = getContract(abi, address);
      return contract.send(action, values)
    })
    .then((txId) => {
      dispatch(flashMessage('txId: ' + txId))
      return blockchain.subscribeTx(txId)
    })
    .then(transaction => transaction.blockNumber)
}

export function submit(dispatch, formName, address, abiName, action, form) {
  dispatch(startSubmit(formName));
  return run(dispatch, address, abiName, action, _.values(form))
    .then((blockNumber) => {
      dispatch(stopSubmit(formName))
      dispatch(reset(formName))
      dispatch(flashMessage('blockNumber: ' + blockNumber))
    })
    .catch(() => {
      dispatch(stopSubmit(formName))
    })
}

export function send(dispatch, address, abiName, action, values) {
  return run(dispatch, address, abiName, action, values)
    .then((blockNumber) => {
      dispatch(flashMessage('blockNumber: ' + blockNumber))
    })
}

export function call(dispatch, formName, contract, action, form) {
  dispatch(startSubmit(formName));
  return contract.call(action, _.values(form))
    .then((result) => {
      dispatch(stopSubmit(formName))
      return result
    })
    .catch(() => {
      dispatch(stopSubmit(formName))
    })
}

export function removeModule(address, name) {
  return (dispatch) => {
    send(dispatch, address, 'Core', 'removeModule', [name])
      .then(() => {
        dispatch(load(address))
      })
  }
}
<commit_msg>fix type ACLStorage<commit_after>import { startSubmit, stopSubmit, reset } from 'redux-form';
import _ from 'lodash'
import { hashHistory } from 'react-router';
import i18next from 'i18next'
import { LOAD, ADD_MODULE } from './actionTypes'
import { loadAbiByName, getContract, blockchain, getTransaction, createModule, createModuleWatch, getModuleAddress } from '../../utils/web3'
import { promiseFor } from '../../utils/helper'
import { flashMessage } from '../app/actions'
import { loadModule as aclLoadModule } from '../acl/actions'
// import { loadModule as tokenLoadModule } from '../token/actions'
// import { loadModule as tokenAclLoadModule } from '../tokenAcl/actions'
// import { loadModule as ambixLoadModule } from '../ambix/actions'
// import { loadModule as marketLoadModule } from '../market/actions'

export function observeModules() {
  const loadModule = {
    acl: aclLoadModule,
    // token: tokenLoadModule,
    // 'token-acl': tokenAclLoadModule,
    // ambix: ambixLoadModule,
    // market: marketLoadModule
  }
  return (dispatch, getState) => {
    blockchain.setSubscribe((bl) => {
      _.forEach(bl.transactions, (txId) => {
        const info = getTransaction(txId);
        const state = getState()
        _.forEach(state.dao.blocks, (block) => {
          _.forEach(block.modules, (module) => {
            if (module.address === info.from || module.address === info.to) {
              dispatch(loadModule[block.type](module.address))
            }
          })
        })
      })
    })
  }
}

export function addModule(type, name, address) {
  return {
    type: ADD_MODULE,
    payload: {
      type,
      name,
      address
    }
  }
}

export function load(daoAddress) {
  return (dispatch) => {
    loadAbiByName('Core')
      .then((abi) => {
        const core = getContract(abi, daoAddress);
        const blocks = [
          {
            name: i18next.t('dao:groupAuditors'),
            type: 'acl',
            modules: []
          },
          {
            name: i18next.t('dao:holder'),
            type: 'holder',
            modules: []
          },
          {
            name: i18next.t('dao:auditor'),
            type: 'auditor',
            modules: []
          },
          {
            name: i18next.t('dao:complier'),
            type: 'complier',
            modules: []
          },
          {
            name: i18next.t('dao:token'),
            type: 'token',
            modules: []
          },
          {
            name: i18next.t('dao:carbonRegistry'),
            type: 'token-acl',
            modules: []
          },
          // {
          //   name: i18next.t('dao:market'),
          //   type: 'market',
          //   modules: []
          // }
        ]
        core.call('first')
          .then(firstAddress => (
            promiseFor(address => address !== '0x0000000000000000000000000000000000000000', (address) => {
              core.call('abiOf', [address])
                .then((type) => {
                  if (type === 'https://github.com/airalab/core/blob/master/sol/acl/ACLStorage.sol') {
                    return 'acl'
                  }
                  if (type === 'tokenAcl') {
                    return 'token-acl'
                  }
                  return type
                })
                .then((type) => {
                  const block = _.find(blocks, ['type', type])
                  if (block) {
                    core.call('getName', [address])
                      .then((name) => {
                        block.modules.push({
                          name,
                          address
                        })
                      })
                  }
                })
              return core.call('next', [address])
            }, firstAddress)
          ))
          .then(() => core.call('name'))
          .then((name) => {
            dispatch({
              type: LOAD,
              payload: {
                address: daoAddress,
                name,
                blocks
              }
            })
          });
        // dispatch(observeModules())
      })
  }
}

export function create(dispatch, module, values) {
  let builderAddress
  let builder
  return getModuleAddress(module)
    .then((address) => {
      builderAddress = address;
      return loadAbiByName(module)
    })
    .then((abi) => {
      builder = getContract(abi, builderAddress)
      return createModule(builder, values)
    })
    .then((txId) => {
      dispatch(flashMessage('txId: ' + txId))
      return createModuleWatch(builder)
    })
}

export function setModule(dispatch, daoAddress, name, address, type) {
  return loadAbiByName('Core')
    .then((abi) => {
      const core = getContract(abi, daoAddress);
      return core.send('setModule', [name, address, type, false])
    })
    .then((txId) => {
      dispatch(flashMessage('txId: ' + txId))
      return blockchain.subscribeTx(txId)
    })
    .then(transaction => transaction.blockNumber)
}

export function submitCreateModule(form, action) {
  return (dispatch) => {
    let builder = false;
    switch (action) {
      case 'core':
        builder = 'BuilderOperator'
        break;
      case 'issuer':
        builder = 'BuilderIssuerLedger'
        break;
      case 'auditor':
        builder = 'BuilderAuditor'
        break;
      case 'complier':
        builder = 'BuilderComplier'
        break;
      case 'market':
        builder = 'BuilderMarket'
        break;
      case 'token':
        builder = 'BuilderTokenEmission'
        break;
      case 'tokenAcl':
        builder = 'BuilderTokenEmissionACL'
        break;
      case 'acl':
        builder = 'BuilderACLStorage'
        break;
      default:
        break;
    }
    if (builder) {
      dispatch(startSubmit('FormCreator'));
      create(dispatch, builder, _.values(form))
        .then((address) => {
          dispatch(stopSubmit('FormCreator'))
          dispatch(reset('FormCreator'))
          dispatch(flashMessage('address: ' + address))
          if (action !== 'core' && action !== 'issuer' && action !== 'auditor' && action !== 'complier') {
            hashHistory.push('/dao/link/' + action + '/' + address)
          }
        })
        .catch((e) => {
          console.log(e);
          dispatch(stopSubmit('FormCreator'))
        })
    }
  }
}

export function submitLinkModule(daoAddress, form) {
  return (dispatch) => {
    dispatch(startSubmit('FormLinkModule'));
    setModule(dispatch, daoAddress, form.name, form.address, form.type)
      .then((blockNumber) => {
        dispatch(stopSubmit('FormLinkModule'))
        dispatch(reset('FormLinkModule'))
        dispatch(flashMessage('blockNumber: ' + blockNumber))
        dispatch(addModule(form.type, form.name, form.address))
      })
      .catch(() => {
        dispatch(stopSubmit('FormLinkModule'))
      })
  }
}

function run(dispatch, address, abiName, action, values) {
  return loadAbiByName(abiName)
    .then((abi) => {
      const contract = getContract(abi, address);
      return contract.send(action, values)
    })
    .then((txId) => {
      dispatch(flashMessage('txId: ' + txId))
      return blockchain.subscribeTx(txId)
    })
    .then(transaction => transaction.blockNumber)
}

export function submit(dispatch, formName, address, abiName, action, form) {
  dispatch(startSubmit(formName));
  return run(dispatch, address, abiName, action, _.values(form))
    .then((blockNumber) => {
      dispatch(stopSubmit(formName))
      dispatch(reset(formName))
      dispatch(flashMessage('blockNumber: ' + blockNumber))
    })
    .catch(() => {
      dispatch(stopSubmit(formName))
    })
}

export function send(dispatch, address, abiName, action, values) {
  return run(dispatch, address, abiName, action, values)
    .then((blockNumber) => {
      dispatch(flashMessage('blockNumber: ' + blockNumber))
    })
}

export function call(dispatch, formName, contract, action, form) {
  dispatch(startSubmit(formName));
  return contract.call(action, _.values(form))
    .then((result) => {
      dispatch(stopSubmit(formName))
      return result
    })
    .catch(() => {
      dispatch(stopSubmit(formName))
    })
}

export function removeModule(address, name) {
  return (dispatch) => {
    send(dispatch, address, 'Core', 'removeModule', [name])
      .then(() => {
        dispatch(load(address))
      })
  }
}
<|endoftext|>


<commit_before>// GLOBAL VARIABLES ================================================
var ROWS = 7;
var COLUMNS = 7;
//==================================================================

//==================MODEL CLASS=====================================
function Model(){
	// Local Variables
	var grid = initGrid(ROWS, COLUMNS); // calls with global vars

	// Fields
	this.grid = grid;

	// Public Methods

	//--Static Methods

	//--Instance Methods

	// Private Methods
	function initGrid(rows, columns) {
		var grid = [];
		for (var i = 0; i < rows; i++) {
			var row = [];
			for (var j = 0; j < columns; j++) {
				row.push("");
			}
			grid.push(row);
		}
		return grid;
	};

	//console.table(grid);  (TESTING)

} // end of class
//==================================================================

//==================CONTROLLER CLASS================================

function Controller(){
	// Static Variables
	var canvasID = document.getElementById('canvas');
	var view = new View(canvasID);
	var model = new Model();
	canvasID.addEventListener("click",nextState,false);

	// Static Methods
	function nextState(e){
		var x_Pos = e.clientX;
		var y_Pos = e.clientY;
		var position = normalize(x_Pos,y_Pos);
		console.log(position.x+","+position.y);

		// will be moved to its own function in due time.
		// quick and dirty check to see if they entered exactly 1 char
		// TODO: check if a-->z
		var letter = prompt("Enter a letter");
		if (letter != "" || letter != null) {  // cancel returns null
			if (letter.length == 1) {
				view.addLetter(letter,position.x, position.y);
				model.grid[position.y][position.x] = letter; // note: opposite
				console.table(model.grid); // TESTING
			} else {
				window.alert("please select a valid letter");
			}
		}
	}

	function normalize(x_Pos,y_Pos){
		var canvasSize = canvasID.getBoundingClientRect();

		var deltaX = (canvasSize.right-canvasSize.left)/COLUMNS;
		var deltaY = (canvasSize.bottom-canvasSize.top)/ROWS;

		// rel_x and rel_y are the grid coordinates starting from (0,0) bottom left
		var rel_x = Math.floor(((x_Pos - canvasSize.left)/(deltaX)));
		var rel_y = Math.floor(((y_Pos - canvasSize.top)/(deltaY)));
		return {x:rel_x,
			    y:rel_y
			   };
	}

} // end of Controller class
//==================================================================

//==================VIEW CLASS======================================

function View(canvasID){
	var width =50;  // eventually will be globals
	var height =50;  // designating width of each cell

	var ctx = canvasID.getContext('2d');

	// Draws the rectangles
	for(var rows = 0; rows < ROWS; rows++) {
		for (var cols = 0; cols < COLUMNS; cols++) {
			ctx.strokeStyle = "black";
			ctx.fillStyle = "yellow";
			ctx.beginPath();
			ctx.lineWidth = 1;
			ctx.rect(width*rows, height*cols, width, height);
			ctx.closePath();
			ctx.fill();
			ctx.stroke();
		}
	}

	this.addLetter = function (letter, x, y) {
		ctx.fillStyle="black";
		ctx.font="25px Georgia";
		ctx.fillText(letter,(15+(x*50)),35+(y*50));
	};

} // end of View Class

<commit_msg>input now requires capital letters to work<commit_after>// GLOBAL VARIABLES ================================================
var ROWS = 7;
var COLUMNS = 7;
//==================================================================

//==================MODEL CLASS=====================================
function Model(){
	// Local Variables
	var grid = initGrid(ROWS, COLUMNS); // calls with global vars

	// Fields
	this.grid = grid;

	// Public Methods

	//--Static Methods

	//--Instance Methods

	// Private Methods
	function initGrid(rows, columns) {
		var grid = [];
		for (var i = 0; i < rows; i++) {
			var row = [];
			for (var j = 0; j < columns; j++) {
				row.push("");
			}
			grid.push(row);
		}
		return grid;
	};

	//console.table(grid);  (TESTING)

} // end of class
//==================================================================

//==================CONTROLLER CLASS================================

function Controller(){
	// Static Variables
	var canvasID = document.getElementById('canvas');
	var view = new View(canvasID);
	var model = new Model();
	canvasID.addEventListener("click",nextState,false);

	// Static Methods
	function nextState(e){
		var x_Pos = e.clientX;
		var y_Pos = e.clientY;
		var position = normalize(x_Pos,y_Pos);
		console.log(position.x+","+position.y);

		// will be moved to its own function in due time.
		// quick and dirty check to see if they entered exactly 1 char
		// TODO: check if a-->z
		var letter = prompt("Enter a letter");
		var capLetters = /[A-Z]/;		// creating a regular expression and setting it to
										// a var. This regex means from A-Z it is true
		if (letter != "" || letter != null) {  // cancel returns null
			if (letter.match(capLetters)){		//If the value has a A-Z in it return true
				if (letter.length == 1) {
					view.addLetter(letter,position.x, position.y);
					model.grid[position.y][position.x] = letter; // note: opposite
					console.table(model.grid); // TESTING
				}
			} else {
				window.alert("please select a valid letter");
			}
		}
	}

	function normalize(x_Pos,y_Pos){
		var canvasSize = canvasID.getBoundingClientRect();

		var deltaX = (canvasSize.right-canvasSize.left)/COLUMNS;
		var deltaY = (canvasSize.bottom-canvasSize.top)/ROWS;

		// rel_x and rel_y are the grid coordinates starting from (0,0) bottom left
		var rel_x = Math.floor(((x_Pos - canvasSize.left)/(deltaX)));
		var rel_y = Math.floor(((y_Pos - canvasSize.top)/(deltaY)));
		return {x:rel_x,
			    y:rel_y
			   };
	}

} // end of Controller class
//==================================================================

//==================VIEW CLASS======================================

function View(canvasID){
	var width =50;  // eventually will be globals
	var height =50;  // designating width of each cell

	var ctx = canvasID.getContext('2d');

	// Draws the rectangles
	for(var rows = 0; rows < ROWS; rows++) {
		for (var cols = 0; cols < COLUMNS; cols++) {
			ctx.strokeStyle = "black";
			ctx.fillStyle = "yellow";
			ctx.beginPath();
			ctx.lineWidth = 1;
			ctx.rect(width*rows, height*cols, width, height);
			ctx.closePath();
			ctx.fill();
			ctx.stroke();
		}
	}

	this.addLetter = function (letter, x, y) {
		ctx.fillStyle="black";
		ctx.font="25px Georgia";
		ctx.fillText(letter,(15+(x*50)),35+(y*50));
	};

} // end of View Class

<|endoftext|>


<commit_before>var irc = require('irc')
var config = require('./config.js')

var bot
var commands

var channel_blocks = {
	private_chat: {
		blocked: false,
		kudos_minus: false,
		kudos_plus: false,
		ultrachord: false,
	},
	main_chat: {
		blocked: false,
		// XXX merge these into identify
		botbrname: false,
		botbrpass: false,
		botbrsync: false,
		kudos_minus: false,
		kudos_plus: false,
		update_ip: false,
	}
}

var commands_aliases = {
	b: 'battle',
	chord: 'ultrachord',
	compo: 'battle',
	g: 'google',
	gi: 'image',
	gif: 'giphy',
	h: 'help',
	i: 'imdb',
	images: 'image',
	img: 'imgur',
	imgr: 'imgur',
	l: 'lyceum',
	ohc: 'ohb',
	pic: 'pix',
	uc: 'ultrachord',
	up: 'uptime',
	w: 'wikipedia',
	wiki: 'wikipedia',
	y: 'youtube',
	yt: 'youtube',
}

var commands_alias_filters = {
	'kudos_minus': /^(.+)\-{2}$/i,
	'kudos_plus': /^(.+)\+{2}$/i,
}

alias_check = command => {
	if (typeof commands_aliases[command] !== 'undefined')
		command = commands_aliases[command]
	return command
}

alias_filter_check = text => {
	for (let key in commands_alias_filters) {
		filter = commands_alias_filters[key];
		if (filter.test(text)) return key;
	}
	return false;
}

command_check = (channel_type, command) => {
	if (channel_blocks[channel_type][command] === false)
		return false
	if (typeof commands[command] === 'undefined')
		return false
	return true
}

command_parser = (from, to, text, info) => {
	let command = ''
	// break text into words
	let words = text.split(' ').filter(e => e !== '')
	// supplement info
	info.from = from
	info.command_prefix = config.command_prefix
	info.words = words
	// interpret solicitor
	let channel
	if (to === config.bot_name) {
		console.log(`PM <${from}> ${text}`)
		channel = 'private_chat'
		info.channel = from
		info.channel_type = channel
	}
	else if (config.irc.channels.indexOf(to) != -1) {
		console.log(`${to} <${from}> ${text}`)
		channel = 'main_chat'
		info.channel = info.args[0]
		info.channel_type = channel
	}

	// check alias filters
	// commands override
	if (words[0].substr(0, 1) !== config.command_prefix) {
		command = alias_filter_check(text);
		if (command !== false) commands[command](info, words);
		return;
	}

	// make sure there's a string to parse! :X
	if (typeof words[0] == 'undefined') return false;

	// check for command prefix
	if (words[0].substr(0, 1) !== config.command_prefix) {
		if (to === config.bot_name) {
			// XXX something is fukt here
			if (from === config.bot_name) {
				console.log('STOP MESSAGING YERSELF!!')
				return false
			}
			info.channel = from
			commands.unknown(info, words)
		}
		return false
	}

	// remove command prefix
	command = words[0].substr(1)

	// abort if command is empty or non-alphabetic (likely an emoticon)
	if (command === '' || !command.match(/^[a-zA-Z]/))
		return false

	// check if the command is an alias
	command = alias_check(command)

	// check channel's blocked commands
	if (command_check(channel, command) === false) {
		commands.blocked(info, words)
		console.log(`"${command}" in #${channel} blocked`)
		return false
	}

	// check for command and call
	if (typeof commands[command] === "function") {
		try {
			let response = commands[command](info, words)
		} catch(err) {
			module.exports.say(info.channel, 'an error hath occured :X')
			console.log(err)
		}
	}
}

module.exports = {

	alias_check: command => {
		return alias_check(command)
	},

	alias_find: command => {
		let alias_list = []
		for (alias in commands_aliases) {
			if (commands_aliases[alias] === command) {
				alias_list.push(alias)
			}
		}
		return alias_list
	},

	command_check: (command, channel_type) => {
		return command_check(command, channel_type)
	},

	command_list: channel_type => {
		let command_list = []
		for (command in commands) {
			if (command_check(channel_type, command)) {
				command_list.push(command)
			}
		}
		return command_list
	},

	initialize: () => {
		bot = new irc.Client(config.irc.server, config.bot_name, {
			userName: config.bot_name.toLowerCase(),
			realName: config.bot_name + ' IRC bot',
			debug: config.irc.debug,
			autoRejoin: config.irc.autoRejoin,
			channels: config.irc.channels
		})

		//commands.init(this)
		commands = require('./irc_commands.js')

		bot.addListener('error', message => {
			console.log(`IRC error:`)
			console.log(message)
		})
		bot.addListener('join', (channel, who) => {
			console.log(`${who} has joined ${channel}`)
		})
		bot.addListener('part', (channel, who) => {
			console.log(`${who} has parted ${channel}`)
		})
		bot.addListener('quit', (channel, who) => {
			console.log(`${who} has quit ${channel}`)
		})
		bot.addListener('message', (from, to, text, info) => {
			command_parser(from, to, text, info)
		})
	},

	say: (channel, text) => {
		function irc_push(channel, text) {
			text = `${config.irc.text_color} ${text}${config.irc.text_color} `
			console.log(`${channel} <${config.bot_name}> ${text}`)
			bot.say(channel, text)
		}
		// is it an array?
		if (Array.isArray(text)) {
			text.forEach(line => {
				irc_push(channel, line)
			})
			return
		}
		// is it just text?
		irc_push(channel, text)
	}
}
<commit_msg>command parser makes sure there are words<commit_after>var irc = require('irc')
var config = require('./config.js')

var bot
var commands

var channel_blocks = {
	private_chat: {
		blocked: false,
		kudos_minus: false,
		kudos_plus: false,
		ultrachord: false,
	},
	main_chat: {
		blocked: false,
		// XXX merge these into identify
		botbrname: false,
		botbrpass: false,
		botbrsync: false,
		kudos_minus: false,
		kudos_plus: false,
		update_ip: false,
	}
}

var commands_aliases = {
	b: 'battle',
	chord: 'ultrachord',
	compo: 'battle',
	g: 'google',
	gi: 'image',
	gif: 'giphy',
	h: 'help',
	i: 'imdb',
	images: 'image',
	img: 'imgur',
	imgr: 'imgur',
	l: 'lyceum',
	ohc: 'ohb',
	pic: 'pix',
	uc: 'ultrachord',
	up: 'uptime',
	w: 'wikipedia',
	wiki: 'wikipedia',
	y: 'youtube',
	yt: 'youtube',
}

var commands_alias_filters = {
	'kudos_minus': /^(.+)\-{2}$/i,
	'kudos_plus': /^(.+)\+{2}$/i,
}

alias_check = command => {
	if (typeof commands_aliases[command] !== 'undefined')
		command = commands_aliases[command]
	return command
}

alias_filter_check = text => {
	for (let key in commands_alias_filters) {
		filter = commands_alias_filters[key];
		if (filter.test(text)) return key;
	}
	return false;
}

command_check = (channel_type, command) => {
	if (channel_blocks[channel_type][command] === false)
		return false
	if (typeof commands[command] === 'undefined')
		return false
	return true
}

command_parser = (from, to, text, info) => {
	let command = ''
	// break text into words
	let words = text.split(' ').filter(e => e !== '')
	if (words.length < 1) return false;
	// supplement info
	info.from = from
	info.command_prefix = config.command_prefix
	info.words = words
	// interpret solicitor
	let channel
	if (to === config.bot_name) {
		console.log(`PM <${from}> ${text}`)
		channel = 'private_chat'
		info.channel = from
		info.channel_type = channel
	}
	else if (config.irc.channels.indexOf(to) != -1) {
		console.log(`${to} <${from}> ${text}`)
		channel = 'main_chat'
		info.channel = info.args[0]
		info.channel_type = channel
	}

	// check alias filters
	// commands override
	if (words[0].substr(0, 1) !== config.command_prefix) {
		command = alias_filter_check(text);
		if (command !== false) commands[command](info, words);
		return;
	}

	// make sure there's a string to parse! :X
	if (typeof words[0] == 'undefined') return false;

	// check for command prefix
	if (words[0].substr(0, 1) !== config.command_prefix) {
		if (to === config.bot_name) {
			// XXX something is fukt here
			if (from === config.bot_name) {
				console.log('STOP MESSAGING YERSELF!!')
				return false
			}
			info.channel = from
			commands.unknown(info, words)
		}
		return false
	}

	// remove command prefix
	command = words[0].substr(1)

	// abort if command is empty or non-alphabetic (likely an emoticon)
	if (command === '' || !command.match(/^[a-zA-Z]/))
		return false

	// check if the command is an alias
	command = alias_check(command)

	// check channel's blocked commands
	if (command_check(channel, command) === false) {
		commands.blocked(info, words)
		console.log(`"${command}" in #${channel} blocked`)
		return false
	}

	// check for command and call
	if (typeof commands[command] === "function") {
		try {
			let response = commands[command](info, words)
		} catch(err) {
			module.exports.say(info.channel, 'an error hath occured :X')
			console.log(err)
		}
	}
}

module.exports = {

	alias_check: command => {
		return alias_check(command)
	},

	alias_find: command => {
		let alias_list = []
		for (alias in commands_aliases) {
			if (commands_aliases[alias] === command) {
				alias_list.push(alias)
			}
		}
		return alias_list
	},

	command_check: (command, channel_type) => {
		return command_check(command, channel_type)
	},

	command_list: channel_type => {
		let command_list = []
		for (command in commands) {
			if (command_check(channel_type, command)) {
				command_list.push(command)
			}
		}
		return command_list
	},

	initialize: () => {
		bot = new irc.Client(config.irc.server, config.bot_name, {
			userName: config.bot_name.toLowerCase(),
			realName: config.bot_name + ' IRC bot',
			debug: config.irc.debug,
			autoRejoin: config.irc.autoRejoin,
			channels: config.irc.channels
		})

		//commands.init(this)
		commands = require('./irc_commands.js')

		bot.addListener('error', message => {
			console.log(`IRC error:`)
			console.log(message)
		})
		bot.addListener('join', (channel, who) => {
			console.log(`${who} has joined ${channel}`)
		})
		bot.addListener('part', (channel, who) => {
			console.log(`${who} has parted ${channel}`)
		})
		bot.addListener('quit', (channel, who) => {
			console.log(`${who} has quit ${channel}`)
		})
		bot.addListener('message', (from, to, text, info) => {
			command_parser(from, to, text, info)
		})
	},

	say: (channel, text) => {
		function irc_push(channel, text) {
			text = `${config.irc.text_color} ${text}${config.irc.text_color} `
			console.log(`${channel} <${config.bot_name}> ${text}`)
			bot.say(channel, text)
		}
		// is it an array?
		if (Array.isArray(text)) {
			text.forEach(line => {
				irc_push(channel, line)
			})
			return
		}
		// is it just text?
		irc_push(channel, text)
	}
}
<|endoftext|>


<commit_before>// GLOBAL VARIABLES ================================================
var ROWS = 7;
var COLUMNS = 7;
//==================================================================

//==================MODEL CLASS=====================================
function Model(){
	// Local Variables
	var grid = initGrid(ROWS, COLUMNS); // calls with global vars

	// Fields
	this.grid = grid;

	// Public Methods

	//--Static Methods

	//--Instance Methods

	// Private Methods
	function initGrid(rows, columns) {
		var grid = [];
		for (var i = 0; i < rows; i++) {
			var row = [];
			for (var j = 0; j < columns; j++) {
				row.push("");
			}
			grid.push(row);
		}
		return grid;
	};

	//console.table(grid);  (TESTING)

} // end of class
//==================================================================

//==================CONTROLLER CLASS================================

function Controller(){
	// Static Variables
	var canvasID = document.getElementById('canvas');
	var view = new View(canvasID);
	var model = new Model();
	canvasID.addEventListener("click",nextState,false);

	// Static Methods
	function nextState(e){
		var x_Pos = e.clientX;
		var y_Pos = e.clientY;
		var position = normalize(x_Pos,y_Pos);
		console.log(position.x+","+position.y);

		// will be moved to its own function in due time.
		// quick and dirty check to see if they entered exactly 1 char
		// TODO: check if a-->z
		var letter = prompt("Enter a letter");
		var capLetters = /[A-Z]/;		// creating a regular expression and setting it to
										// a var. This regex means from A-Z it is true
		if (letter != "" || letter != null) {  // cancel returns null
			if (letter.match(capLetters)){		//If the value has a A-Z in it return true
				if (letter.length == 1) {
					view.addLetter(letter,position.x, position.y);
					model.grid[position.y][position.x] = letter; // note: opposite
					console.table(model.grid); // TESTING
				}
			} else {
				window.alert("please select a valid letter");
			}
		}
	}

	function normalize(x_Pos,y_Pos){
		var canvasSize = canvasID.getBoundingClientRect();

		var deltaX = (canvasSize.right-canvasSize.left)/COLUMNS;
		var deltaY = (canvasSize.bottom-canvasSize.top)/ROWS;

		// rel_x and rel_y are the grid coordinates starting from (0,0) bottom left
		var rel_x = Math.floor(((x_Pos - canvasSize.left)/(deltaX)));
		var rel_y = Math.floor(((y_Pos - canvasSize.top)/(deltaY)));
		return {x:rel_x,
			    y:rel_y
			   };
	}

} // end of Controller class
//==================================================================

//==================VIEW CLASS======================================

function View(canvasID){
	var width =50;  // eventually will be globals
	var height =50;  // designating width of each cell

	var ctx = canvasID.getContext('2d');

	// Draws the rectangles
	for(var rows = 0; rows < ROWS; rows++) {
		for (var cols = 0; cols < COLUMNS; cols++) {
			ctx.strokeStyle = "black";
			ctx.fillStyle = "yellow";
			ctx.beginPath();
			ctx.lineWidth = 1;
			ctx.rect(width*rows, height*cols, width, height);
			ctx.closePath();
			ctx.fill();
			ctx.stroke();
		}
	}

	this.addLetter = function (letter, x, y) {
		ctx.fillStyle="black";
		ctx.font="25px Georgia";
		ctx.fillText(letter,(15+(x*50)),35+(y*50));
	};

} // end of View Class

<commit_msg>Lowercase to upper case conversion<commit_after>// GLOBAL VARIABLES ================================================
var ROWS = 7;
var COLUMNS = 7;
//==================================================================

//==================MODEL CLASS=====================================
function Model(){
	// Local Variables
	var grid = initGrid(ROWS, COLUMNS); // calls with global vars

	// Fields
	this.grid = grid;

	// Public Methods

	//--Static Methods

	//--Instance Methods

	// Private Methods
	function initGrid(rows, columns) {
		var grid = [];
		for (var i = 0; i < rows; i++) {
			var row = [];
			for (var j = 0; j < columns; j++) {
				row.push("");
			}
			grid.push(row);
		}
		return grid;
	};

	//console.table(grid);  (TESTING)

} // end of class
//==================================================================

//==================CONTROLLER CLASS================================

function Controller(){
	// Static Variables
	var canvasID = document.getElementById('canvas');
	var view = new View(canvasID);
	var model = new Model();
	canvasID.addEventListener("click",nextState,false);

	// Static Methods
	function nextState(e){
		var x_Pos = e.clientX;
		var y_Pos = e.clientY;
		var position = normalize(x_Pos,y_Pos);
		console.log(position.x+","+position.y);

		// will be moved to its own function in due time.
		// quick and dirty check to see if they entered exactly 1 char
		// TODO: check if a-->z
		var letter = prompt("Enter a letter");

		// creating a regular expression and setting it to
		// a var. This regex means from a-z and A-Z it is true
		var aLetters = /[A-Z]|[a-z]/;

		if (letter != "" || letter != null) {  // cancel returns null
			if (letter.match(aLetters)){		//If the value has a-z or A-Z in it return true
				if (letter.length == 1) {
					// changing the letters to their uppercase when printing to the view and model
					view.addLetter(letter.toUpperCase(),position.x, position.y);
					model.grid[position.y][position.x] = letter.toUpperCase(); // note: opposite
					console.table(model.grid); // TESTING
				}
			} else {
				window.alert("Please select a valid letter");
			}
		}
	}

	function normalize(x_Pos,y_Pos){
		var canvasSize = canvasID.getBoundingClientRect();

		var deltaX = (canvasSize.right-canvasSize.left)/COLUMNS;
		var deltaY = (canvasSize.bottom-canvasSize.top)/ROWS;

		// rel_x and rel_y are the grid coordinates starting from (0,0) bottom left
		var rel_x = Math.floor(((x_Pos - canvasSize.left)/(deltaX)));
		var rel_y = Math.floor(((y_Pos - canvasSize.top)/(deltaY)));
		return {x:rel_x,
			    y:rel_y
			   };
	}

} // end of Controller class
//==================================================================

//==================VIEW CLASS======================================

function View(canvasID){
	var width =50;  // eventually will be globals
	var height =50;  // designating width of each cell

	var ctx = canvasID.getContext('2d');

	// Draws the rectangles
	for(var rows = 0; rows < ROWS; rows++) {
		for (var cols = 0; cols < COLUMNS; cols++) {
			ctx.strokeStyle = "black";
			ctx.fillStyle = "yellow";
			ctx.beginPath();
			ctx.lineWidth = 1;
			ctx.rect(width*rows, height*cols, width, height);
			ctx.closePath();
			ctx.fill();
			ctx.stroke();
		}
	}

	this.addLetter = function (letter, x, y) {
		ctx.fillStyle="black";
		ctx.font="25px Georgia";
		ctx.fillText(letter,(15+(x*50)),35+(y*50));
	};

} // end of View Class

<|endoftext|>


<commit_before>// getResource for the global scope:
function getResource(name) {
	// Get a list of all resource in the Global prototype and scan for the
	// given resource
	var resources = app.getPrototype('Global').getResources();
	// scan backwards to get newer versions first (does this work?)
	for (var i = resources.length - 1; i >= 0; i--) {
	    var r = resources[i];
	    if (r.exists() && r.getShortName().equals(name))
			return r;
	}
	return null;
}

function encodeMD5(str) {
	return Packages.helma.util.MD5Encoder.encode(str);
}

function encodeHSA1(str) {
	var algorithm = java.security.MessageDigest.getInstance('SHA-1');
	var digest = algorithm.digest(new java.lang.String(str).getBytes());
	res.push();
	for (var i = 0; i < digest.length; i++) {
		var b = digest[i] & 0xff;
		if (b < 0x10) res.write('0');
		res.write(java.lang.Integer.toHexString(b));
	}
	return res.pop();
}

function encodeUrl(str) {
	return str ? Packages.helma.util.UrlEncoded.encode(str, 'UTF-8').replace('%20', '+') : str;
}

function encodeJs(str) {
	return str ? (str = uneval(str)).substring(1, str.length - 1) : str;
}

function encodeHex(str) {
	if (!str) return str;
	res.push();
	for (var i = 0; i < str.length; i++) {
		// TODO: why escape twice???
		res.write('\\\\x');
		res.write(str.charCodeAt(i).toString(16));
	}
	return res.pop();
}

// encodeSql is the same as encodeJs:
var encodeSql = encodeJs;

function decodeUrl(str) {
	return str ? Packages.helma.util.UrlEncoded.decode(str, 'UTF-8') : str;
}

// the opposite of encode:
function decode(str) {
	str = Packages.org.htmlparser.util.Translate.decode(str);
	return str.replaceAll('
', '\n');
}

function executeProcess() {
	if (arguments.length == 1) {
		var command = arguments[0];
	} else {
		var command = [];
		for (var i = 0; i < arguments.length; i++) {
			command.push(arguments[i]);
		}
	}
	var process = java.lang.Runtime.getRuntime().exec(command);
	var exitValue = process.waitFor();

	function readStream(stream) {
		var reader = new java.io.BufferedReader(new java.io.InputStreamReader(stream));
		res.push();
		var line, first = true;
		while ((line = reader.readLine()) != null) {
			if (first) first = false;
			else res.write('\n');
			res.write(line);
		}
		return res.pop();
	}

	return {
		command: command,
		result: readStream(process.getInputStream()),
		error: readStream(process.getErrorStream()),
		exitValue: exitValue
	};
}

renderLink = function(content, urlOptions, htmlOptions, out) {
	var url = '';
	if (urlOptions) {
		if (typeof urlOptions == 'string') url = urlOptions;
		else if (urlOptions instanceof HopObject) url = urlOptions.href();
		else if (urlOptions.href) url = urlOptions.href;
		else if (urlOptions.object) url = urlOptions.object.href(urlOptions.action);
		if (urlOptions.query)
			url += (urlOptions.query[0] == '?' ? '' : url.indexOf('?') != -1 ? '&' : '?') + urlOptions.query;
	}
	var attributes = '';
	if (htmlOptions) {
		var onClick;
		// TODO: make confirm work with destination, and maybe onClick
		if (htmlOptions.onClick) {
			// Convert single quotes to double quotes, as we're using single quotes
			// for the HTML attribute here (due to the use of uneval bellow)
			onClick = htmlOptions.onClick.replace(/'/mgi, '"');
		} else if (htmlOptions.update) {
			onClick = 'DomElement.get("' + htmlOptions.update + '").load("' + url + '"); return false;';
			url = '#';
		} else if (htmlOptions.popup) {
			var params = htmlOptions.popup.clone();
			delete params.title;
			if (htmlOptions.confirm)
				params.confirm = htmlOptions.confirm;
			onClick = 'Window.open("' + url + '", "' + (htmlOptions.popup.title || content.urlize()) + '", ' + Json.encode(params) + '); return false;';
			url = '#';
		} else if (htmlOptions.confirm) {
			onClick = 'return confirm("' + encodeJs(htmlOptions.confirm) + '")';
		}
		if (htmlOptions.attributes) {
			attributes = htmlOptions.attributes.each(function(val, key) {
				this.push(key + '="' + val + '"');
			}, ['']).join(' ');
		}
		// Use single quotes for onClick, due to uneval above.
		if (onClick)
			attributes += " onclick='" + onClick + "'";
	}

	out.write('');
	out.write(content);
	out.write('');
}.toRender();

// Simple helper for debugging

function print() {
	var str = Array.create(arguments).join(' ');
	app.log(str);
	res.write(str + '
');
}
<commit_msg>Added global sleep function to let the thread sleep.<commit_after>// getResource for the global scope:
function getResource(name) {
	// Get a list of all resource in the Global prototype and scan for the
	// given resource
	var resources = app.getPrototype('Global').getResources();
	// scan backwards to get newer versions first (does this work?)
	for (var i = resources.length - 1; i >= 0; i--) {
	    var r = resources[i];
	    if (r.exists() && r.getShortName().equals(name))
			return r;
	}
	return null;
}

function encodeMD5(str) {
	return Packages.helma.util.MD5Encoder.encode(str);
}

function encodeHSA1(str) {
	var algorithm = java.security.MessageDigest.getInstance('SHA-1');
	var digest = algorithm.digest(new java.lang.String(str).getBytes());
	res.push();
	for (var i = 0; i < digest.length; i++) {
		var b = digest[i] & 0xff;
		if (b < 0x10) res.write('0');
		res.write(java.lang.Integer.toHexString(b));
	}
	return res.pop();
}

function encodeUrl(str) {
	return str ? Packages.helma.util.UrlEncoded.encode(str, 'UTF-8').replace('%20', '+') : str;
}

function encodeJs(str) {
	return str ? (str = uneval(str)).substring(1, str.length - 1) : str;
}

function encodeHex(str) {
	if (!str) return str;
	res.push();
	for (var i = 0; i < str.length; i++) {
		// TODO: why escape twice???
		res.write('\\\\x');
		res.write(str.charCodeAt(i).toString(16));
	}
	return res.pop();
}

// encodeSql is the same as encodeJs:
var encodeSql = encodeJs;

function decodeUrl(str) {
	return str ? Packages.helma.util.UrlEncoded.decode(str, 'UTF-8') : str;
}

// the opposite of encode:
function decode(str) {
	str = Packages.org.htmlparser.util.Translate.decode(str);
	return str.replaceAll('
', '\n');
}

function executeProcess() {
	if (arguments.length == 1) {
		var command = arguments[0];
	} else {
		var command = [];
		for (var i = 0; i < arguments.length; i++) {
			command.push(arguments[i]);
		}
	}
	var process = java.lang.Runtime.getRuntime().exec(command);
	var exitValue = process.waitFor();

	function readStream(stream) {
		var reader = new java.io.BufferedReader(new java.io.InputStreamReader(stream));
		res.push();
		var line, first = true;
		while ((line = reader.readLine()) != null) {
			if (first) first = false;
			else res.write('\n');
			res.write(line);
		}
		return res.pop();
	}

	return {
		command: command,
		result: readStream(process.getInputStream()),
		error: readStream(process.getErrorStream()),
		exitValue: exitValue
	};
}

renderLink = function(content, urlOptions, htmlOptions, out) {
	var url = '';
	if (urlOptions) {
		if (typeof urlOptions == 'string') url = urlOptions;
		else if (urlOptions instanceof HopObject) url = urlOptions.href();
		else if (urlOptions.href) url = urlOptions.href;
		else if (urlOptions.object) url = urlOptions.object.href(urlOptions.action);
		if (urlOptions.query)
			url += (urlOptions.query[0] == '?' ? '' : url.indexOf('?') != -1 ? '&' : '?') + urlOptions.query;
	}
	var attributes = '';
	if (htmlOptions) {
		var onClick;
		// TODO: make confirm work with destination, and maybe onClick
		if (htmlOptions.onClick) {
			// Convert single quotes to double quotes, as we're using single quotes
			// for the HTML attribute here (due to the use of uneval bellow)
			onClick = htmlOptions.onClick.replace(/'/mgi, '"');
		} else if (htmlOptions.update) {
			onClick = 'DomElement.get("' + htmlOptions.update + '").load("' + url + '"); return false;';
			url = '#';
		} else if (htmlOptions.popup) {
			var params = htmlOptions.popup.clone();
			delete params.title;
			if (htmlOptions.confirm)
				params.confirm = htmlOptions.confirm;
			onClick = 'Window.open("' + url + '", "' + (htmlOptions.popup.title || content.urlize()) + '", ' + Json.encode(params) + '); return false;';
			url = '#';
		} else if (htmlOptions.confirm) {
			onClick = 'return confirm("' + encodeJs(htmlOptions.confirm) + '")';
		}
		if (htmlOptions.attributes) {
			attributes = htmlOptions.attributes.each(function(val, key) {
				this.push(key + '="' + val + '"');
			}, ['']).join(' ');
		}
		// Use single quotes for onClick, due to uneval above.
		if (onClick)
			attributes += " onclick='" + onClick + "'";
	}

	out.write('');
	out.write(content);
	out.write('');
}.toRender();

// Simple helper for debugging

function print() {
	var str = Array.create(arguments).join(' ');
	app.log(str);
	res.write(str + '
');
}

function sleep(milliseconds) {
	java.lang.Thread.sleep(milliseconds);
}<|endoftext|>


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

const argv = require('minimist')(process.argv.slice(2));
const colors = require('ansi-colors');
const fs = require('fs-extra');
const gulp = require('gulp-help')(require('gulp'));
const log = require('fancy-log');

const year = new Date().getFullYear();

/*eslint "max-len": 0*/

function pascalCase(str) {
  return str[0].toUpperCase() + str.slice(1).replace(/-([a-z])/g,
      function(g) { return g[1].toUpperCase(); });
}

function getValidatorFile(name) {
  return `#
# Copyright ${year} The AMP HTML Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS-IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the license.
#

tags: {  # ${name}
  html_format: AMP
  tag_name: "SCRIPT"
  extension_spec: {
    name: "${name}"
    version: "0.1"
    version: "latest"
  }
  attr_lists: "common-extension-attrs"
}
tags: {  # <${name}>
  html_format: AMP
  tag_name: "${name.toUpperCase()}"
  requires_extension: "${name}"
  attr_lists: "extended-amp-global"
  spec_url: "https://www.ampproject.org/docs/reference/components/${name}"
  amp_layout: {
    supported_layouts: RESPONSIVE
  }
}
`;
}

function getMarkdownExtensionFile(name) {
  return `

# <a name="\`${name}\`"> \`${name}\`

    Description
    FILL THIS IN

    Availability
    FILL THIS IN

    Required Script
    <script async custom-element="amp-form" src="https://cdn.ampproject.org/v0/${name}-0.1.js"></script>

    Supported Layouts
    FILL THIS IN

    Examples
    FILL THIS IN

## Behavior

FILL THIS IN. What does this extension do?

## Attributes

FILL THIS IN. Does this extension allow for properties to configure?

## Validation
See [${name} rules](https://github.com/ampproject/amphtml/blob/master/extensions/${name}/validator-${name}.protoascii) in the AMP validator specification.
`;
}

function getJsTestExtensionFile(name) {
  return `/**
 * Copyright ${year} The AMP HTML Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import '../${name}';

describes.realWin('${name}', {
  amp: {
    extensions: ['${name}'],
  },
}, env => {

  let win;
  let element;

  beforeEach(() => {
    win = env.win;
    element = win.document.createElement('${name}');
    win.document.body.appendChild(element);
  });

  it('should have hello world when built', () => {
    element.build();
    expect(element.querySelector('div').textContent).to.equal('hello world');
  });
});
`;
}

function getJsExtensionFile(name) {
  const className = pascalCase(name);
  return `/**
 * Copyright ${year} The AMP HTML Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {Layout} from '../../../src/layout';

export class ${className} extends AMP.BaseElement {

  /** @param {!AmpElement} element */
  constructor(element) {
    super(element);

    /** @private {string} */
    this.myText_ = 'hello world';

    /** @private {?Element} */
    this.container_ = null;
  }

  /** @override */
  buildCallback() {
    this.container_ = this.win.document.createElement('div');
    this.container_.textContent = this.myText_;
    this.element.appendChild(this.container_);
    this.applyFillContent(this.container_, /* replacedContent */ true);
  }

  /** @override */
  isLayoutSupported(layout) {
    return layout == Layout.RESPONSIVE;
  }
}

AMP.registerElement('${name}', ${className});
`;
}

function getExamplesFile(name) {
  return `<!doctype html>

  <meta charset="utf-8">
  <title>${name} example</title>
  <link rel="canonical" href="amps.html">
  <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">

  <${name} layout="responsive" width="150" height="80"></${name}>

`;
}

function makeExtension() {
  if (!argv.name) {
    log(colors.red(
        'Error! Please pass in the "--name" flag with a value'));
  }
  const {name} = argv;
  const examplesFile = getExamplesFile(name);

  fs.mkdirpSync(`extensions/${name}/0.1/test`);
  fs.writeFileSync(`extensions/${name}/${name}.md`,
      getMarkdownExtensionFile(name));
  fs.writeFileSync(`extensions/${name}/validator-${name}.protoascii`,
      getValidatorFile(name));
  fs.writeFileSync(`extensions/${name}/0.1/${name}.js`,
      getJsExtensionFile(name));
  fs.writeFileSync(`extensions/${name}/0.1/test/test-${name}.js`,
      getJsTestExtensionFile(name));
  fs.writeFileSync(`extensions/${name}/0.1/test/validator-${name}.html`,
      examplesFile);

  const examplesFileValidatorOut = examplesFile.trim().split('\n')
      .map(line => `|  ${line}`)
      .join('\n');

  fs.writeFileSync(`extensions/${name}/0.1/test/validator-${name}.out`,
      ['PASS', examplesFileValidatorOut].join('\n'));

  fs.writeFileSync(`examples/${name}.amp.html`,
      examplesFile);
}

gulp.task('make-extension', 'Create an extension skeleton', makeExtension, {
  options: {
    name: '  The name of the extension. Preferable prefixed with `amp-*`',
  },
});
<commit_msg>🐛 Tweaks to the extension generator (#18628)<commit_after>/**
 * Copyright 2017 The AMP HTML Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
'use strict';

const argv = require('minimist')(process.argv.slice(2));
const colors = require('ansi-colors');
const fs = require('fs-extra');
const gulp = require('gulp-help')(require('gulp'));
const log = require('fancy-log');

const year = new Date().getFullYear();

/*eslint "max-len": 0*/

function pascalCase(str) {
  return str[0].toUpperCase() + str.slice(1).replace(/-([a-z])/g,
      function(g) { return g[1].toUpperCase(); });
}

function getValidatorFile(name) {
  return `#
# Copyright ${year} The AMP HTML Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS-IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the license.
#

tags: {  # ${name}
  html_format: AMP
  tag_name: "SCRIPT"
  extension_spec: {
    name: "${name}"
    version: "0.1"
    version: "latest"
  }
  attr_lists: "common-extension-attrs"
}
tags: {  # <${name}>
  html_format: AMP
  tag_name: "${name.toUpperCase()}"
  requires_extension: "${name}"
  attr_lists: "extended-amp-global"
  spec_url: "https://www.ampproject.org/docs/reference/components/${name}"
  amp_layout: {
    supported_layouts: RESPONSIVE
  }
}
`;
}

function getMarkdownExtensionFile(name) {
  return `

# \`${name}\`

    Description
    FILL THIS IN

    Availability
    FILL THIS IN

    Required Script
    <script async custom-element="${name}" src="https://cdn.ampproject.org/v0/${name}-0.1.js"></script>

    Supported Layouts
    FILL THIS IN

    Examples
    FILL THIS IN

## Behavior

FILL THIS IN. What does this extension do?

## Attributes

FILL THIS IN. Does this extension allow for properties to configure?

## Validation
See [${name} rules](https://github.com/ampproject/amphtml/blob/master/extensions/${name}/validator-${name}.protoascii) in the AMP validator specification.
`;
}

function getJsTestExtensionFile(name) {
  return `/**
 * Copyright ${year} The AMP HTML Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import '../${name}';

describes.realWin('${name}', {
  amp: {
    extensions: ['${name}'],
  },
}, env => {

  let win;
  let element;

  beforeEach(() => {
    win = env.win;
    element = win.document.createElement('${name}');
    win.document.body.appendChild(element);
  });

  it('should have hello world when built', () => {
    element.build();
    expect(element.querySelector('div').textContent).to.equal('hello world');
  });
});
`;
}

function getJsExtensionFile(name) {
  const className = pascalCase(name);
  return `/**
 * Copyright ${year} The AMP HTML Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {Layout} from '../../../src/layout';

export class ${className} extends AMP.BaseElement {

  /** @param {!AmpElement} element */
  constructor(element) {
    super(element);

    /** @private {string} */
    this.myText_ = 'hello world';

    /** @private {?Element} */
    this.container_ = null;
  }

  /** @override */
  buildCallback() {
    this.container_ = this.win.document.createElement('div');
    this.container_.textContent = this.myText_;
    this.element.appendChild(this.container_);
    this.applyFillContent(this.container_, /* replacedContent */ true);
  }

  /** @override */
  isLayoutSupported(layout) {
    return layout == Layout.RESPONSIVE;
  }
}

AMP.registerElement('${name}', ${className});
`;
}

function getExamplesFile(name) {
  return `<!doctype html>

  <meta charset="utf-8">
  <title>${name} example</title>
  <link rel="canonical" href="amps.html">
  <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">

  <${name} layout="responsive" width="150" height="80"></${name}>

`;
}

function makeExtension() {
  if (!argv.name) {
    log(colors.red(
        'Error! Please pass in the "--name" flag with a value'));
  }
  const {name} = argv;
  const examplesFile = getExamplesFile(name);

  fs.mkdirpSync(`extensions/${name}/0.1/test`);
  fs.writeFileSync(`extensions/${name}/${name}.md`,
      getMarkdownExtensionFile(name));
  fs.writeFileSync(`extensions/${name}/validator-${name}.protoascii`,
      getValidatorFile(name));
  fs.writeFileSync(`extensions/${name}/0.1/${name}.js`,
      getJsExtensionFile(name));
  fs.writeFileSync(`extensions/${name}/0.1/test/test-${name}.js`,
      getJsTestExtensionFile(name));
  fs.writeFileSync(`extensions/${name}/0.1/test/validator-${name}.html`,
      examplesFile);

  const examplesFileValidatorOut = examplesFile.trim().split('\n')
      .map(line => `|  ${line}`)
      .join('\n');

  fs.writeFileSync(`extensions/${name}/0.1/test/validator-${name}.out`,
      ['PASS', examplesFileValidatorOut].join('\n'));

  fs.writeFileSync(`examples/${name}.amp.html`,
      examplesFile);
}

gulp.task('make-extension', 'Create an extension skeleton', makeExtension, {
  options: {
    name: '  The name of the extension. Preferable prefixed with `amp-*`',
  },
});
<|endoftext|>


<commit_before>Components.utils.import("resource://hatenabookmark/modules/00-utils.jsm");
loadPrecedingModules();
const EXPORTED_SYMBOLS = [];
//const EXPORTED_SYMBOLS = ['selector2xpath'];

function convertHatenaStarSiteConfigToSiteInfoItem(text) {
    let config = decodeJSON(text);
    let items = [];
    for (let domain in config) {
        let entries = config[domain];
        let domainPattern = '^https?://'
        domainPattern += (domain.charCodeAt(0) === 42 /* '*' */)
                         ? '(?:[\w-]+\.)*' + domain.substring(2)
                         : domain;
        for (let i = 0; i < entries.length; i++) {
            let entry = entries[i];
            let path = entry.path || '';
            let urlPattern = domainPattern +
                             ((path.charCodeAt(0) === 94 /* '^' */)
                              ? path.substring(1)
                              : '.*' + path);
            let entryNodes = entry.entryNodes;
            if (!entryNodes) continue;
            let paraSelector;
            // 同一パス下での複数エントリには非対応
            for (paraSelector in entryNodes) break;
            let paraInfos = entryNodes[paraSelector];
            items.push({
                domain:     urlPattern,
                paragraph:  selector2xpath(paraSelector),
                link:       selector2xpath(paraInfos.uri || 'parent'),
                annotation: selector2xpath(paraInfos.container || 'parent'),
                annotationPosition: 'last',
            });
        }
    }
    return items;
}

function selector2xpath(selector) {
    switch (selector) {
    case 'parent':
        return 'self::*';

    case 'window.location':
    case 'document.location':
        return getLinkToCurrentURI;

    //case 'document.title':
    //    return '""';
    }

    selector = selector.replace(/\s+/g, ' ').replace(/ ?([,>]) ?/g, '$1');
    return selector.split(',').map(singleSelector2xpath).join(' | ');
}

function singleSelector2xpath(selector) {
    return 'descendant::' +
        selector.split(/([ >])/).map(selectorPart2xpath).join('');
}

function selectorPart2xpath(part, i) {
    if (i & 1) return (part === ' ') ? '/descendant::' : '/child::';

    let elementPart = /^(?:[\w-]+|\*)/.exec(part);
    let element;
    if (elementPart) {
        element = elementPart[0];
        part = part.substring(element.length);
    } else {
        element = '*';
    }
    return part
        ? element + '[' + part.split(/(?=[#.:])/).map(classes2xpath).join(' and ') + ']'
        : element;
}

function classes2xpath(kindOfClass) {
    let first = kindOfClass.charCodeAt(0);
    if (first === 35 /* '#' */)
        return '@id = "' + kindOfClass.substring(1) + '"';
    if (first === 46 /* '.' */)
        return 'contains(concat(" ", normalize-space(@class), " "), " ' +
               kindOfClass.substring(1) + ' ")';

    switch (kindOfClass) {
    case ':first-child':
    case ':first':
    case ':nth-child(1)':
        return 'not(preceding-sibling::*)';

    case':last-child':
        return 'not(following-sibling::*)';
    }
    // Assume it is an nth-child pseudo class.
    let index = (/\d+/.exec(kindOfClass) || [0])[0];
    return 'count(preceding-sibling::*) = ' + (index - 1);
}

function getLinkToCurrentURI(context) {
    let doc = context.ownerDocument || context;
    let a = doc.createElementNS(XHTML_NS, 'a');
    a.href = doc.defaultView.location.href;
    return a;
}

SiteInfoSet.converters.hatenastar = convertHatenaStarSiteConfigToSiteInfoItem;
<commit_msg>ドメイン名正規表現のエスケープ漏れを修正。<commit_after>Components.utils.import("resource://hatenabookmark/modules/00-utils.jsm");
loadPrecedingModules();
const EXPORTED_SYMBOLS = [];
//const EXPORTED_SYMBOLS = ['selector2xpath'];

function convertHatenaStarSiteConfigToSiteInfoItem(text) {
    let config = decodeJSON(text);
    let items = [];
    for (let domain in config) {
        let entries = config[domain];
        let domainPattern = '^https?://'
        domainPattern += (domain.charCodeAt(0) === 42 /* '*' */)
            ? '(?:[\w-]+\.)*' + domain.substring(2).replace(/\W/g, '\\$&')
            : domain.replace(/\W/g, '\\$&');
        for (let i = 0; i < entries.length; i++) {
            let entry = entries[i];
            let path = entry.path || '';
            let urlPattern = domainPattern +
                             ((path.charCodeAt(0) === 94 /* '^' */)
                              ? path.substring(1)
                              : '.*' + path);
            let entryNodes = entry.entryNodes;
            if (!entryNodes) continue;
            let paraSelector;
            // 同一パス下での複数エントリには非対応
            for (paraSelector in entryNodes) break;
            let paraInfos = entryNodes[paraSelector];
            items.push({
                domain:     urlPattern,
                paragraph:  selector2xpath(paraSelector),
                link:       selector2xpath(paraInfos.uri || 'parent'),
                annotation: selector2xpath(paraInfos.container || 'parent'),
                annotationPosition: 'last',
            });
        }
    }
    return items;
}

function selector2xpath(selector) {
    switch (selector) {
    case 'parent':
        return 'self::*';

    case 'window.location':
    case 'document.location':
        return getLinkToCurrentURI;

    //case 'document.title':
    //    return '""';
    }

    selector = selector.replace(/\s+/g, ' ').replace(/ ?([,>]) ?/g, '$1');
    return selector.split(',').map(singleSelector2xpath).join(' | ');
}

function singleSelector2xpath(selector) {
    return 'descendant::' +
        selector.split(/([ >])/).map(selectorPart2xpath).join('');
}

function selectorPart2xpath(part, i) {
    if (i & 1) return (part === ' ') ? '/descendant::' : '/child::';

    let elementPart = /^(?:[\w-]+|\*)/.exec(part);
    let element;
    if (elementPart) {
        element = elementPart[0];
        part = part.substring(element.length);
    } else {
        element = '*';
    }
    return part
        ? element + '[' + part.split(/(?=[#.:])/).map(classes2xpath).join(' and ') + ']'
        : element;
}

function classes2xpath(kindOfClass) {
    let first = kindOfClass.charCodeAt(0);
    if (first === 35 /* '#' */)
        return '@id = "' + kindOfClass.substring(1) + '"';
    if (first === 46 /* '.' */)
        return 'contains(concat(" ", normalize-space(@class), " "), " ' +
               kindOfClass.substring(1) + ' ")';

    switch (kindOfClass) {
    case ':first-child':
    case ':first':
    case ':nth-child(1)':
        return 'not(preceding-sibling::*)';

    case':last-child':
        return 'not(following-sibling::*)';
    }
    // Assume it is an nth-child pseudo class.
    let index = (/\d+/.exec(kindOfClass) || [0])[0];
    return 'count(preceding-sibling::*) = ' + (index - 1);
}

function getLinkToCurrentURI(context) {
    let doc = context.ownerDocument || context;
    let a = doc.createElementNS(XHTML_NS, 'a');
    a.href = doc.defaultView.location.href;
    return a;
}

SiteInfoSet.converters.hatenastar = convertHatenaStarSiteConfigToSiteInfoItem;
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import Loadable from 'react-loadable';

import Spinner from '../Spinner';

const CODEMIRROR_CONFIG = {
  lineNumbers: true,
  tabSize: 2,
  mode: 'yaml',
  keyMap: 'sublime',
  autoCloseBrackets: true,
  matchBrackets: true,
  showCursorWhenSelecting: true,
  viewportMargin: Infinity,
  gutters: ['CodeMirror-linenumbers'],
  extraKeys: {
    'Ctrl-Left': 'goSubwordLeft',
    'Ctrl-Right': 'goSubwordRight',
    'Alt-Left': 'goGroupLeft',
    'Alt-Right': 'goGroupRight'
  }
};

class FormYAMLEdtiorField extends React.Component {
  static propTypes = {
    name: PropTypes.string,
    value: PropTypes.string,
    CodeMirror: PropTypes.func
  };

  componentDidMount() {
    const { CodeMirror } = this.props;

    this.editor = CodeMirror.fromTextArea(
      this.input,
      CODEMIRROR_CONFIG
    );
  }

  componentWillUnmount() {
    if (this.editor) {
      this.editor.toTextArea();
      delete this.editor;
    }
  }

  render() {
    return (

        <textarea
          name={this.props.name}
          defaultValue={this.props.value}
          ref={(input) => this.input = input}
        />

    );
  }
}

const CODEMIRROR_BUFFER = 8;
const CODEMIRROR_LINE_HEIGHT = 18;

const FormYAMLEdtiorFieldLoader = (props) => {
  // Here's a dynamic loader for editor that does some magical stuff. It tries
  // to attempt the size of the editor before we load it, this way the page
  // doesn't change in size after we load in Codemirror.
  const ApproximateHeightLoader = () => {
    const lines = props.value.split("\n").length;
    const height = CODEMIRROR_BUFFER + (lines * CODEMIRROR_LINE_HEIGHT);

    return (

        <Spinner /> Loading Editor…

    );
  };

  ApproximateHeightLoader.propTypes = {
    value: PropTypes.string
  };

  // This loads Codemirror and all of its addons.
  const LoadableCodeMirror = Loadable.Map({
    loader: {
      CodeMirror: () => (
        import('./codemirror').then((module) => (
          // HACK: Add a "zero" delay after the module has
          // loaded, to allow their styles to take effect
          new Promise((resolve) => {
            setTimeout(() => resolve(module.default), 0);
          })
        ))
      )
    },

    loading() {
      return (
        <ApproximateHeightLoader />
      );
    },

    render(loaded, props) {
      return (
        <FormYAMLEdtiorField
          CodeMirror={loaded.CodeMirror}
          name={props.name}
          value={props.value}
        />
      );
    }
  });

  return (
    <LoadableCodeMirror {...props} />
  );
};

FormYAMLEdtiorFieldLoader.propTypes = {
  name: PropTypes.string,
  value: PropTypes.string
};

export default FormYAMLEdtiorFieldLoader;
<commit_msg>Take into consideration codemirror minimum height<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import Loadable from 'react-loadable';

import Spinner from '../Spinner';

const CODEMIRROR_CONFIG = {
  lineNumbers: true,
  tabSize: 2,
  mode: 'yaml',
  keyMap: 'sublime',
  autoCloseBrackets: true,
  matchBrackets: true,
  showCursorWhenSelecting: true,
  viewportMargin: Infinity,
  gutters: ['CodeMirror-linenumbers'],
  extraKeys: {
    'Ctrl-Left': 'goSubwordLeft',
    'Ctrl-Right': 'goSubwordRight',
    'Alt-Left': 'goGroupLeft',
    'Alt-Right': 'goGroupRight'
  }
};

class FormYAMLEdtiorField extends React.Component {
  static propTypes = {
    name: PropTypes.string,
    value: PropTypes.string,
    CodeMirror: PropTypes.func
  };

  componentDidMount() {
    const { CodeMirror } = this.props;

    this.editor = CodeMirror.fromTextArea(
      this.input,
      CODEMIRROR_CONFIG
    );
  }

  componentWillUnmount() {
    if (this.editor) {
      this.editor.toTextArea();
      delete this.editor;
    }
  }

  render() {
    return (

        <textarea
          name={this.props.name}
          defaultValue={this.props.value}
          ref={(input) => this.input = input}
        />

    );
  }
}

const CODEMIRROR_BUFFER = 8;
const CODEMIRROR_LINE_HEIGHT = 18;
const CODEMIRROR_MIN_HEIGHT = 150;

const FormYAMLEdtiorFieldLoader = (props) => {
  // Here's a dynamic loader for editor that does some magical stuff. It tries
  // to attempt the size of the editor before we load it, this way the page
  // doesn't change in size after we load in Codemirror.
  const ApproximateHeightLoader = () => {
    const lines = props.value.split("\n").length;

    let height = CODEMIRROR_BUFFER + (lines * CODEMIRROR_LINE_HEIGHT);
    if (CODEMIRROR_MIN_HEIGHT > height) {
      height = CODEMIRROR_MIN_HEIGHT;
    }

    return (

        <Spinner /> Loading Editor…

    );
  };

  ApproximateHeightLoader.propTypes = {
    value: PropTypes.string
  };

  // This loads Codemirror and all of its addons.
  const LoadableCodeMirror = Loadable.Map({
    loader: {
      CodeMirror: () => (
        import('./codemirror').then((module) => (
          // HACK: Add a "zero" delay after the module has
          // loaded, to allow their styles to take effect
          new Promise((resolve) => {
            setTimeout(() => resolve(module.default), 0);
          })
        ))
      )
    },

    loading() {
      return (
        <ApproximateHeightLoader />
      );
    },

    render(loaded, props) {
      return (
        <FormYAMLEdtiorField
          CodeMirror={loaded.CodeMirror}
          name={props.name}
          value={props.value}
        />
      );
    }
  });

  return (
    <LoadableCodeMirror {...props} />
  );
};

FormYAMLEdtiorFieldLoader.propTypes = {
  name: PropTypes.string,
  value: PropTypes.string
};

export default FormYAMLEdtiorFieldLoader;
<|endoftext|>