<commit_before>// Opening for events
const eventTitle = getElementByClassName('event-title', 0)
const eventSubtitle = getElementByClassName('event-subtitle', 0)
const eventDetails = getElementByClassName('event-details', 0)
// Remove display classes on init for hero tabs
eventTitle.classList.remove('fade-move')
eventSubtitle.classList.remove('fade-move')
eventDetails.classList.remove('fade-move')
// Fade in first slide
eventTitle.classList.add('display')
eventSubtitle.classList.add('display')
eventDetails.classList.add('display')
// Email signup form
setTimeout(() => changeEmailContainerBackground(getElementByClassName('email-container-background', 0)), 600)

// Event listener for if reg form is closed
const regFormModalStatus = getElementByClassName('modal-status registration', 0)
const regFormModal = getElementByClassName('modal registration', 0)
const regFormModalWindow = getElementByClassName('modal-window registration', 0)
const regFormButtons = getElementsByClassName('button register')
for (let i = 0; i < regFormButtons.length; i++) {
	onClick(regFormButtons[i], () => {
		// Prevent background from scrolling
		document.body.style.overflow = 'hidden'
		// Prepare for fade in
		regFormModal.style.opacity = '0'
		// Unhide modal
		setTimeout(() => regFormModalStatus.style.display = 'block', 100)
		// Fade in modal window
		setTimeout(() => regFormModal.style.opacity = '1.0', 200)
		// Show reg form: browser error that doesn’t show opacity of children unless scrolled to
		setTimeout(() => {
			regFormModalWindow.scrollTo(0, 0)
			regFormModalWindow.onscroll = () => regFormModal.style.opacity = '1.0'
		}, 300)
	})
}

const regFormClose = getElementByClassName('reg-form-close', 0)
onClick(regFormClose, () => {
	document.body.style.overflow = 'visible'
	regFormModal.style.opacity = '0'
	setTimeout(() => regFormModalStatus.style.display = 'none', 200)
})

// Event summary “Read more...” expansion
getElementByClassName('text read-more', 0).addEventListener('mouseover', () => {
	hideElement(getElementByClassName('text read-more'))
	hideElement(getElementByClassName('text summary'))
	getElementByClassName('text description').classList.add('display')
	setTimeout(() => getElementByClassName('text description display').classList.add('fade'), 100)
})

// Prevent accidental submission of form through 'enter' key
onKeyPress(document, e => {
	if (isInput(e.target) && e.which === 13) {
		e.preventDefault()
		return false
	}
})

let countries = [{value:'AF',label:'Afghanistan'},{value:'AX',label:'Åland Islands'},{value:'AL',label:'Albania'},{value:'DZ',label:'Algeria'},{value:'AS',label:'American Samoa'},{value:'AD',label:'Andorra'},{value:'AO',label:'Angola'},{value:'AI',label:'Anguilla'},{value:'AQ',label:'Antarctica'},{value:'AG',label:'Antigua and Barbuda'},{value:'AR',label:'Argentina'},{value:'AM',label:'Armenia'},{value:'AW',label:'Aruba'},{value:'AU',label:'Australia'},{value:'AT',label:'Austria'},{value:'AZ',label:'Azerbaijan'},{value:'BS',label:'Bahamas'},{value:'BH',label:'Bahrain'},{value:'BD',label:'Bangladesh'},{value:'BB',label:'Barbados'},{value:'BY',label:'Belarus'},{value:'BE',label:'Belgium'},{value:'BZ',label:'Belize'},{value:'BJ',label:'Benin'},{value:'BM',label:'Bermuda'},{value:'BT',label:'Bhutan'},{value:'BO',label:'Bolivia'},{value:'BA',label:'Bosnia and Herzegovina'},{value:'BW',label:'Botswana'},{value:'BV',label:'Bouvet Island'},{value:'BR',label:'Brazil'},{value:'IO',label:'British Indian Ocean Territory'},{value:'BN',label:'Brunei Darussalam'},{value:'BG',label:'Bulgaria'},{value:'BF',label:'Burkina Faso'},{value:'BI',label:'Burundi'},{value:'KH',label:'Cambodia'},{value:'CM',label:'Cameroon'},{value:'CA',label:'Canada'},{value:'CV',label:'Cape Verde'},{value:'KY',label:'Cayman Islands'},{value:'CF',label:'Central African Republic'},{value:'TD',label:'Chad'},{value:'CL',label:'Chile'},{value:'CN',label:'China, People’s Republic of'},{value:'CX',label:'Christmas Island'},{value:'CC',label:'Cocos (Keeling) Islands'},{value:'CO',label:'Colombia'},{value:'KM',label:'Comoros'},{value:'CG',label:'Congo'},{value:'CD',label:'Congo, The Democratic Republic of the'},{value:'CK',label:'Cook Islands'},{value:'CR',label:'Costa Rica'},{value:'CI',label:'Cote D’Ivoire'},{value:'HR',label:'Croatia'},{value:'CU',label:'Cuba'},{value:'CY',label:'Cyprus'},{value:'CZ',label:'Czech Republic'},{value:'DK',label:'Denmark'},{value:'DJ',label:'Djibouti'},{value:'DM',label:'Dominica'},{value:'DO',label:'Dominican Republic'},{value:'EC',label:'Ecuador'},{value:'EG',label:'Egypt'},{value:'SV',label:'El Salvador'},{value:'GQ',label:'Equatorial Guinea'},{value:'ER',label:'Eritrea'},{value:'EE',label:'Estonia'},{value:'ET',label:'Ethiopia'},{value:'FK',label:'Falkland Islands (Malvinas)'},{value:'FO',label:'Faroe Islands'},{value:'FJ',label:'Fiji'},{value:'FI',label:'Finland'},{value:'FR',label:'France'},{value:'GF',label:'French Guiana'},{value:'PF',label:'French Polynesia'},{value:'TF',label:'French Southern Territories'},{value:'GA',label:'Gabon'},{value:'GM',label:'Gambia'},{value:'GE',label:'Georgia'},{value:'DE',label:'Germany'},{value:'GH',label:'Ghana'},{value:'GI',label:'Gibraltar'},{value:'GR',label:'Greece'},{value:'GL',label:'Greenland'},{value:'GD',label:'Grenada'},{value:'GP',label:'Guadeloupe'},{value:'GU',label:'Guam'},{value:'GT',label:'Guatemala'},{value:'GG',label:'Guernsey'},{value:'GN',label:'Guinea'},{value:'GW',label:'Guinea-Bissau'},{value:'GY',label:'Guyana'},{value:'HT',label:'Haiti'},{value:'HM',label:'Heard Island and Mcdonald Islands'},{value:'VA',label:'Holy See (Vatican City State)'},{value:'HN',label:'Honduras'},{value:'HK',label:'Hong Kong'},{value:'HU',label:'Hungary'},{value:'IS',label:'Iceland'},{value:'IN',label:'India'},{value:'ID',label:'Indonesia'},{value:'IR',label:'Iran, Islamic Republic Of'},{value:'IQ',label:'Iraq'},{value:'IE',label:'Ireland'},{value:'IM',label:'Isle of Man'},{value:'IL',label:'Israel'},{value:'IT',label:'Italy'},{value:'JM',label:'Jamaica'},{value:'JP',label:'Japan'},{value:'JE',label:'Jersey'},{value:'JO',label:'Jordan'},{value:'KZ',label:'Kazakhstan'},{value:'KE',label:'Kenya'},{value:'KI',label:'Kiribati'},{value:'KP',label:'Democratic People’s Republic of Korea'},{value:'KR',label:'Korea, Republic of'},{value:'XK',label:'Kosovo'},{value:'KW',label:'Kuwait'},{value:'KG',label:'Kyrgyzstan'},{value:'LA',label:'Lao People’s Democratic Republic'},{value:'LV',label:'Latvia'},{value:'LB',label:'Lebanon'},{value:'LS',label:'Lesotho'},{value:'LR',label:'Liberia'},{value:'LY',label:'Libyan Arab Jamahiriya'},{value:'LI',label:'Liechtenstein'},{value:'LT',label:'Lithuania'},{value:'LU',label:'Luxembourg'},{value:'MO',label:'Macao'},{value:'MK',label:'Macedonia, The Former Yugoslav Republic of'},{value:'MG',label:'Madagascar'},{value:'MW',label:'Malawi'},{value:'MY',label:'Malaysia'},{value:'MV',label:'Maldives'},{value:'ML',label:'Mali'},{value:'MT',label:'Malta'},{value:'MH',label:'Marshall Islands'},{value:'MQ',label:'Martinique'},{value:'MR',label:'Mauritania'},{value:'MU',label:'Mauritius'},{value:'YT',label:'Mayotte'},{value:'MX',label:'Mexico'},{value:'FM',label:'Micronesia, Federated States of'},{value:'MD',label:'Moldova, Republic of'},{value:'MC',label:'Monaco'},{value:'MN',label:'Mongolia'},{value:'ME',label:'Montenegro'},{value:'MS',label:'Montserrat'},{value:'MA',label:'Morocco'},{value:'MZ',label:'Mozambique'},{value:'MM',label:'Myanmar'},{value:'NA',label:'Namibia'},{value:'NR',label:'Nauru'},{value:'NP',label:'Nepal'},{value:'NL',label:'Netherlands'},{value:'AN',label:'Netherlands Antilles'},{value:'NC',label:'New Caledonia'},{value:'NZ',label:'New Zealand'},{value:'NI',label:'Nicaragua'},{value:'NE',label:'Niger'},{value:'NG',label:'Nigeria'},{value:'NU',label:'Niue'},{value:'NF',label:'Norfolk Island'},{value:'MP',label:'Northern Mariana Islands'},{value:'NO',label:'Norway'},{value:'OM',label:'Oman'},{value:'PK',label:'Pakistan'},{value:'PW',label:'Palau'},{value:'PS',label:'Palestine, State of'},{value:'PA',label:'Panama'},{value:'PG',label:'Papua New Guinea'},{value:'PY',label:'Paraguay'},{value:'PE',label:'Peru'},{value:'PH',label:'Philippines'},{value:'PN',label:'Pitcairn'},{value:'PL',label:'Poland'},{value:'PT',label:'Portugal'},{value:'PR',label:'Puerto Rico'},{value:'QA',label:'Qatar'},{value:'RE',label:'Reunion'},{value:'RO',label:'Romania'},{value:'RU',label:'Russian Federation'},{value:'RW',label:'Rwanda'},{value:'SH',label:'Saint Helena'},{value:'KN',label:'Saint Kitts and Nevis'},{value:'LC',label:'Saint Lucia'},{value:'PM',label:'Saint Pierre and Miquelon'},{value:'VC',label:'Saint Vincent and the Grenadines'},{value:'WS',label:'Samoa'},{value:'SM',label:'San Marino'},{value:'ST',label:'Sao Tome and Principe'},{value:'SA',label:'Saudi Arabia'},{value:'SN',label:'Senegal'},{value:'RS',label:'Serbia'},{value:'SC',label:'Seychelles'},{value:'SL',label:'Sierra Leone'},{value:'SG',label:'Singapore'},{value:'SK',label:'Slovakia'},{value:'SI',label:'Slovenia'},{value:'SB',label:'Solomon Islands'},{value:'SO',label:'Somalia'},{value:'ZA',label:'South Africa'},{value:'GS',label:'South Georgia and the South Sandwich Islands'},{value:'ES',label:'Spain'},{value:'LK',label:'Sri Lanka'},{value:'SD',label:'Sudan'},{value:'SR',label:'Suriname'},{value:'SJ',label:'Svalbard and Jan Mayen'},{value:'SZ',label:'Swaziland'},{value:'SE',label:'Sweden'},{value:'CH',label:'Switzerland'},{value:'SY',label:'Syrian Arab Republic'},{value:'TW',label:'Taiwan, Republic of China'},{value:'TJ',label:'Tajikistan'},{value:'TZ',label:'Tanzania, United Republic of'},{value:'TH',label:'Thailand'},{value:'TL',label:'Timor-Leste'},{value:'TG',label:'Togo'},{value:'TK',label:'Tokelau'},{value:'TO',label:'Tonga'},{value:'TT',label:'Trinidad and Tobago'},{value:'TN',label:'Tunisia'},{value:'TR',label:'Turkey'},{value:'TM',label:'Turkmenistan'},{value:'TC',label:'Turks and Caicos Islands'},{value:'TV',label:'Tuvalu'},{value:'UG',label:'Uganda'},{value:'UA',label:'Ukraine'},{value:'AE',label:'United Arab Emirates'},{value:'GB',label:'United Kingdom'},{value:'US',label:'United States'},{value:'UM',label:'United States Minor Outlying Islands'},{value:'UY',label:'Uruguay'},{value:'UZ',label:'Uzbekistan'},{value:'VU',label:'Vanuatu'},{value:'VE',label:'Venezuela'},{value:'VN',label:'Viet Nam'},{value:'VG',label:'Virgin Islands, British'},{value:'VI',label:'Virgin Islands, U.S.'},{value:'WF',label:'Wallis and Futuna'},{value:'EH',label:'Western Sahara'},{value:'YE',label:'Yemen'},{value:'ZM',label:'Zambia'},{value:'ZW',label:'Zimbabwe'}]

// Countries
if (getElementById('country')) {
	for(let i in countries) {
		let option = document.createElement('option')
		option.text = countries[i].label
		option.value = countries[i].value
		option.selected = countries[i] === 'United States'
			? true
			: false
		appendSelect(getElementById('country'), option)
	}
}

// Load reg form scripts
const baseScriptUrl = 'https://ecstaticliving.github.io/ecstaticliving.com/dev/events/'
const scripts = ['elements', 'functions', 'onchange', 'webflow', 'payment']
// Load scripts synchronously, one after another, to make sure hierarchy is respected.
const loadScript = index => {
	let js = document.createElement('script')
	js.src = baseScriptUrl + scripts[index] + '.js'
	js.onload = () => {
		// Once final script has loaded, initialise
		if (scripts[index] === 'payment' && (page() === 'Event' || page() === 'Update')) {
			resetForm()
			scriptsHaveBeenLoaded = true
		}
		else {
			loadScript(index + 1)
		}
	}
	document.head.appendChild(js)
}
loadScript(0)
<commit_msg>Reg form modal display.<commit_after>// Opening for events
const eventTitle = getElementByClassName('event-title', 0)
const eventSubtitle = getElementByClassName('event-subtitle', 0)
const eventDetails = getElementByClassName('event-details', 0)
// Remove display classes on init for hero tabs
eventTitle.classList.remove('fade-move')
eventSubtitle.classList.remove('fade-move')
eventDetails.classList.remove('fade-move')
// Fade in first slide
eventTitle.classList.add('display')
eventSubtitle.classList.add('display')
eventDetails.classList.add('display')
// Email signup form
setTimeout(() => changeEmailContainerBackground(getElementByClassName('email-container-background', 0)), 600)

// Event listener for if reg form is closed
const regFormModalStatus = getElementByClassName('modal-status registration', 0)
const regFormModal = getElementByClassName('modal registration', 0)
const regFormModalWindow = getElementByClassName('modal-window registration', 0)
const regFormButtons = getElementsByClassName('button register')
for (let i = 0; i < regFormButtons.length; i++) {
	onClick(regFormButtons[i], () => {
		// Prevent background from scrolling
		document.body.style.overflow = 'hidden'
		// Prepare for fade in
		regFormModal.style.opacity = '0'
		// Unhide modal
		setTimeout(() => regFormModalStatus.style.display = 'block', 100)
		// Fade in modal window
		setTimeout(() => regFormModal.style.opacity = '1.0', 200)
		// Show reg form: browser error that doesn’t show opacity of children unless scrolled to
		setTimeout(() => {
			// regFormModalWindow.scrollTo(0, 0)
			regFormModalWindow.onscroll = () => regFormModal.style.opacity = '1.0'
		}, 300)
	})
}

const regFormClose = getElementByClassName('reg-form-close', 0)
onClick(regFormClose, () => {
	document.body.style.overflow = 'visible'
	regFormModal.style.opacity = '0'
	setTimeout(() => regFormModalStatus.style.display = 'none', 200)
})

// Event summary “Read more...” expansion
getElementByClassName('text read-more', 0).addEventListener('mouseover', () => {
	hideElement(getElementByClassName('text read-more'))
	hideElement(getElementByClassName('text summary'))
	getElementByClassName('text description').classList.add('display')
	setTimeout(() => getElementByClassName('text description display').classList.add('fade'), 100)
})

// Prevent accidental submission of form through 'enter' key
onKeyPress(document, e => {
	if (isInput(e.target) && e.which === 13) {
		e.preventDefault()
		return false
	}
})

let countries = [{value:'AF',label:'Afghanistan'},{value:'AX',label:'Åland Islands'},{value:'AL',label:'Albania'},{value:'DZ',label:'Algeria'},{value:'AS',label:'American Samoa'},{value:'AD',label:'Andorra'},{value:'AO',label:'Angola'},{value:'AI',label:'Anguilla'},{value:'AQ',label:'Antarctica'},{value:'AG',label:'Antigua and Barbuda'},{value:'AR',label:'Argentina'},{value:'AM',label:'Armenia'},{value:'AW',label:'Aruba'},{value:'AU',label:'Australia'},{value:'AT',label:'Austria'},{value:'AZ',label:'Azerbaijan'},{value:'BS',label:'Bahamas'},{value:'BH',label:'Bahrain'},{value:'BD',label:'Bangladesh'},{value:'BB',label:'Barbados'},{value:'BY',label:'Belarus'},{value:'BE',label:'Belgium'},{value:'BZ',label:'Belize'},{value:'BJ',label:'Benin'},{value:'BM',label:'Bermuda'},{value:'BT',label:'Bhutan'},{value:'BO',label:'Bolivia'},{value:'BA',label:'Bosnia and Herzegovina'},{value:'BW',label:'Botswana'},{value:'BV',label:'Bouvet Island'},{value:'BR',label:'Brazil'},{value:'IO',label:'British Indian Ocean Territory'},{value:'BN',label:'Brunei Darussalam'},{value:'BG',label:'Bulgaria'},{value:'BF',label:'Burkina Faso'},{value:'BI',label:'Burundi'},{value:'KH',label:'Cambodia'},{value:'CM',label:'Cameroon'},{value:'CA',label:'Canada'},{value:'CV',label:'Cape Verde'},{value:'KY',label:'Cayman Islands'},{value:'CF',label:'Central African Republic'},{value:'TD',label:'Chad'},{value:'CL',label:'Chile'},{value:'CN',label:'China, People’s Republic of'},{value:'CX',label:'Christmas Island'},{value:'CC',label:'Cocos (Keeling) Islands'},{value:'CO',label:'Colombia'},{value:'KM',label:'Comoros'},{value:'CG',label:'Congo'},{value:'CD',label:'Congo, The Democratic Republic of the'},{value:'CK',label:'Cook Islands'},{value:'CR',label:'Costa Rica'},{value:'CI',label:'Cote D’Ivoire'},{value:'HR',label:'Croatia'},{value:'CU',label:'Cuba'},{value:'CY',label:'Cyprus'},{value:'CZ',label:'Czech Republic'},{value:'DK',label:'Denmark'},{value:'DJ',label:'Djibouti'},{value:'DM',label:'Dominica'},{value:'DO',label:'Dominican Republic'},{value:'EC',label:'Ecuador'},{value:'EG',label:'Egypt'},{value:'SV',label:'El Salvador'},{value:'GQ',label:'Equatorial Guinea'},{value:'ER',label:'Eritrea'},{value:'EE',label:'Estonia'},{value:'ET',label:'Ethiopia'},{value:'FK',label:'Falkland Islands (Malvinas)'},{value:'FO',label:'Faroe Islands'},{value:'FJ',label:'Fiji'},{value:'FI',label:'Finland'},{value:'FR',label:'France'},{value:'GF',label:'French Guiana'},{value:'PF',label:'French Polynesia'},{value:'TF',label:'French Southern Territories'},{value:'GA',label:'Gabon'},{value:'GM',label:'Gambia'},{value:'GE',label:'Georgia'},{value:'DE',label:'Germany'},{value:'GH',label:'Ghana'},{value:'GI',label:'Gibraltar'},{value:'GR',label:'Greece'},{value:'GL',label:'Greenland'},{value:'GD',label:'Grenada'},{value:'GP',label:'Guadeloupe'},{value:'GU',label:'Guam'},{value:'GT',label:'Guatemala'},{value:'GG',label:'Guernsey'},{value:'GN',label:'Guinea'},{value:'GW',label:'Guinea-Bissau'},{value:'GY',label:'Guyana'},{value:'HT',label:'Haiti'},{value:'HM',label:'Heard Island and Mcdonald Islands'},{value:'VA',label:'Holy See (Vatican City State)'},{value:'HN',label:'Honduras'},{value:'HK',label:'Hong Kong'},{value:'HU',label:'Hungary'},{value:'IS',label:'Iceland'},{value:'IN',label:'India'},{value:'ID',label:'Indonesia'},{value:'IR',label:'Iran, Islamic Republic Of'},{value:'IQ',label:'Iraq'},{value:'IE',label:'Ireland'},{value:'IM',label:'Isle of Man'},{value:'IL',label:'Israel'},{value:'IT',label:'Italy'},{value:'JM',label:'Jamaica'},{value:'JP',label:'Japan'},{value:'JE',label:'Jersey'},{value:'JO',label:'Jordan'},{value:'KZ',label:'Kazakhstan'},{value:'KE',label:'Kenya'},{value:'KI',label:'Kiribati'},{value:'KP',label:'Democratic People’s Republic of Korea'},{value:'KR',label:'Korea, Republic of'},{value:'XK',label:'Kosovo'},{value:'KW',label:'Kuwait'},{value:'KG',label:'Kyrgyzstan'},{value:'LA',label:'Lao People’s Democratic Republic'},{value:'LV',label:'Latvia'},{value:'LB',label:'Lebanon'},{value:'LS',label:'Lesotho'},{value:'LR',label:'Liberia'},{value:'LY',label:'Libyan Arab Jamahiriya'},{value:'LI',label:'Liechtenstein'},{value:'LT',label:'Lithuania'},{value:'LU',label:'Luxembourg'},{value:'MO',label:'Macao'},{value:'MK',label:'Macedonia, The Former Yugoslav Republic of'},{value:'MG',label:'Madagascar'},{value:'MW',label:'Malawi'},{value:'MY',label:'Malaysia'},{value:'MV',label:'Maldives'},{value:'ML',label:'Mali'},{value:'MT',label:'Malta'},{value:'MH',label:'Marshall Islands'},{value:'MQ',label:'Martinique'},{value:'MR',label:'Mauritania'},{value:'MU',label:'Mauritius'},{value:'YT',label:'Mayotte'},{value:'MX',label:'Mexico'},{value:'FM',label:'Micronesia, Federated States of'},{value:'MD',label:'Moldova, Republic of'},{value:'MC',label:'Monaco'},{value:'MN',label:'Mongolia'},{value:'ME',label:'Montenegro'},{value:'MS',label:'Montserrat'},{value:'MA',label:'Morocco'},{value:'MZ',label:'Mozambique'},{value:'MM',label:'Myanmar'},{value:'NA',label:'Namibia'},{value:'NR',label:'Nauru'},{value:'NP',label:'Nepal'},{value:'NL',label:'Netherlands'},{value:'AN',label:'Netherlands Antilles'},{value:'NC',label:'New Caledonia'},{value:'NZ',label:'New Zealand'},{value:'NI',label:'Nicaragua'},{value:'NE',label:'Niger'},{value:'NG',label:'Nigeria'},{value:'NU',label:'Niue'},{value:'NF',label:'Norfolk Island'},{value:'MP',label:'Northern Mariana Islands'},{value:'NO',label:'Norway'},{value:'OM',label:'Oman'},{value:'PK',label:'Pakistan'},{value:'PW',label:'Palau'},{value:'PS',label:'Palestine, State of'},{value:'PA',label:'Panama'},{value:'PG',label:'Papua New Guinea'},{value:'PY',label:'Paraguay'},{value:'PE',label:'Peru'},{value:'PH',label:'Philippines'},{value:'PN',label:'Pitcairn'},{value:'PL',label:'Poland'},{value:'PT',label:'Portugal'},{value:'PR',label:'Puerto Rico'},{value:'QA',label:'Qatar'},{value:'RE',label:'Reunion'},{value:'RO',label:'Romania'},{value:'RU',label:'Russian Federation'},{value:'RW',label:'Rwanda'},{value:'SH',label:'Saint Helena'},{value:'KN',label:'Saint Kitts and Nevis'},{value:'LC',label:'Saint Lucia'},{value:'PM',label:'Saint Pierre and Miquelon'},{value:'VC',label:'Saint Vincent and the Grenadines'},{value:'WS',label:'Samoa'},{value:'SM',label:'San Marino'},{value:'ST',label:'Sao Tome and Principe'},{value:'SA',label:'Saudi Arabia'},{value:'SN',label:'Senegal'},{value:'RS',label:'Serbia'},{value:'SC',label:'Seychelles'},{value:'SL',label:'Sierra Leone'},{value:'SG',label:'Singapore'},{value:'SK',label:'Slovakia'},{value:'SI',label:'Slovenia'},{value:'SB',label:'Solomon Islands'},{value:'SO',label:'Somalia'},{value:'ZA',label:'South Africa'},{value:'GS',label:'South Georgia and the South Sandwich Islands'},{value:'ES',label:'Spain'},{value:'LK',label:'Sri Lanka'},{value:'SD',label:'Sudan'},{value:'SR',label:'Suriname'},{value:'SJ',label:'Svalbard and Jan Mayen'},{value:'SZ',label:'Swaziland'},{value:'SE',label:'Sweden'},{value:'CH',label:'Switzerland'},{value:'SY',label:'Syrian Arab Republic'},{value:'TW',label:'Taiwan, Republic of China'},{value:'TJ',label:'Tajikistan'},{value:'TZ',label:'Tanzania, United Republic of'},{value:'TH',label:'Thailand'},{value:'TL',label:'Timor-Leste'},{value:'TG',label:'Togo'},{value:'TK',label:'Tokelau'},{value:'TO',label:'Tonga'},{value:'TT',label:'Trinidad and Tobago'},{value:'TN',label:'Tunisia'},{value:'TR',label:'Turkey'},{value:'TM',label:'Turkmenistan'},{value:'TC',label:'Turks and Caicos Islands'},{value:'TV',label:'Tuvalu'},{value:'UG',label:'Uganda'},{value:'UA',label:'Ukraine'},{value:'AE',label:'United Arab Emirates'},{value:'GB',label:'United Kingdom'},{value:'US',label:'United States'},{value:'UM',label:'United States Minor Outlying Islands'},{value:'UY',label:'Uruguay'},{value:'UZ',label:'Uzbekistan'},{value:'VU',label:'Vanuatu'},{value:'VE',label:'Venezuela'},{value:'VN',label:'Viet Nam'},{value:'VG',label:'Virgin Islands, British'},{value:'VI',label:'Virgin Islands, U.S.'},{value:'WF',label:'Wallis and Futuna'},{value:'EH',label:'Western Sahara'},{value:'YE',label:'Yemen'},{value:'ZM',label:'Zambia'},{value:'ZW',label:'Zimbabwe'}]

// Countries
if (getElementById('country')) {
	for(let i in countries) {
		let option = document.createElement('option')
		option.text = countries[i].label
		option.value = countries[i].value
		option.selected = countries[i] === 'United States'
			? true
			: false
		appendSelect(getElementById('country'), option)
	}
}

// Load reg form scripts
const baseScriptUrl = 'https://ecstaticliving.github.io/ecstaticliving.com/dev/events/'
const scripts = ['elements', 'functions', 'onchange', 'webflow', 'payment']
// Load scripts synchronously, one after another, to make sure hierarchy is respected.
const loadScript = index => {
	let js = document.createElement('script')
	js.src = baseScriptUrl + scripts[index] + '.js'
	js.onload = () => {
		// Once final script has loaded, initialise
		if (scripts[index] === 'payment' && (page() === 'Event' || page() === 'Update')) {
			resetForm()
			scriptsHaveBeenLoaded = true
		}
		else {
			loadScript(index + 1)
		}
	}
	document.head.appendChild(js)
}
loadScript(0)
<|endoftext|>


<commit_before>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You 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.
 */

var sys = require('sys');
var path = require('path');
var http = require('util/http');

var sprintf = require('extern/sprintf').sprintf;

var config = {
  'short_description': 'Print log file for a specified service',
  'long_description': 'Print a log file for a specified service. ' +
                      'If a --follow switch is provided, new data is ' +
                      'printed as soon as it is available.',
  'required_arguments' : [['name', 'Service name']],
  'optional_arguments': [['bytes', 'How many bytes from the end of the log file to print']],
  'options': [
    {
      names: ['--follow', '-F'],
      dest: 'follow',
      action: 'store_true',
      desc: 'Output new data as some as it is available (aka tail -F)'
    }
  ],
  'uses_global_options': ['remote']
};

function handle_command(args) {
  // Return 500 bytes from the end of the log file by default
  var bytes = args.bytes || '1024';
  var service_name = args.name;

  var remote_path = path.join('/', 'services', service_name, 'tail', bytes);
  if (args.follow) {
    remote_path = path.join(remote_path, 'follow');
  }

  // Tack on a trailing /
  remote_path = path.join(remote_path, '/');

  var opts = {
    method: 'GET',
    path: remote_path
  };

  http.build_request(args.remote, opts, function(err, request) {
    if (err) {
      sys.puts('Error: ' + err.message);
    }

    function on_data(chunk) {
      sys.print(chunk);
    }

    request.on('response', function(response) {
      var body = '';

      if (response.statusCode !== 200) {
        response.on('data', function(chunk) {
          body += chunk;
        });
        response.on('end', function() {
          try {
            sys.puts('Error: ' + JSON.parse(body).message);
          }
          catch (e) {
            sys.puts('Error: invalid response');
          }
        });
      }

      else {
        response.setEncoding('ascii');
        response.on('data', on_data);
      }
    });

    // Send the request
    request.end();
  });
}

exports.config = config;
exports.handle_command = handle_command;
<commit_msg>add missing error handler in 'services tail'<commit_after>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You 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.
 */

var sys = require('sys');
var path = require('path');
var http = require('util/http');

var sprintf = require('extern/sprintf').sprintf;

var config = {
  'short_description': 'Print log file for a specified service',
  'long_description': 'Print a log file for a specified service. ' +
                      'If a --follow switch is provided, new data is ' +
                      'printed as soon as it is available.',
  'required_arguments' : [['name', 'Service name']],
  'optional_arguments': [['bytes', 'How many bytes from the end of the log file to print']],
  'options': [
    {
      names: ['--follow', '-F'],
      dest: 'follow',
      action: 'store_true',
      desc: 'Output new data as some as it is available (aka tail -F)'
    }
  ],
  'uses_global_options': ['remote']
};

function handle_command(args) {
  // Return 500 bytes from the end of the log file by default
  var bytes = args.bytes || '1024';
  var service_name = args.name;

  var remote_path = path.join('/', 'services', service_name, 'tail', bytes);
  if (args.follow) {
    remote_path = path.join(remote_path, 'follow');
  }

  // Tack on a trailing /
  remote_path = path.join(remote_path, '/');

  var opts = {
    method: 'GET',
    path: remote_path
  };

  http.build_request(args.remote, opts, function(err, request) {
    if (err) {
      sys.puts('Error: ' + err.message);
      return;
    }

    request.on('error', function(err) {
      sys.puts('Error: ' + err.message);
      return;
    });

    function on_data(chunk) {
      sys.print(chunk);
    }

    request.on('response', function(response) {
      var body = '';

      if (response.statusCode !== 200) {
        response.on('data', function(chunk) {
          body += chunk;
        });
        response.on('end', function() {
          try {
            sys.puts('Error: ' + JSON.parse(body).message);
          }
          catch (e) {
            sys.puts('Error: invalid response');
          }
        });
      }

      else {
        response.setEncoding('ascii');
        response.on('data', on_data);
      }
    });

    // Send the request
    request.end();
  });
}

exports.config = config;
exports.handle_command = handle_command;
<|endoftext|>


<commit_before>'use strict';

var _ = require('lodash');
var modelHelper = require('./_helper');

var _extend = _.extend;

module.exports = function (config) {
  function Book(data) {
  }

  /**
   *
   * [distance] (number|string): distance radius in kilometers when number. Default 50km
   * */
  Book.findSome = function (text, limit) {
    var queryObj = _extend({
      body: {
          filter: {
            limit: { value: limit || 10 }
          }
      }
    }, baseBookData);

    queryObj.body.query = {
      match: {
        _all: {
          query: text,
          operator: "or"
        }
      }
    };

    return db.search(queryObj)
    .then(modelHelper.dbResultFromSearchToData);
  };

  var baseBookData = {
    index: 'books',
    type: 'book'
  };
  var db = config.db;
  return Book;
};
<commit_msg>removed blank line<commit_after>'use strict';

var _ = require('lodash');
var modelHelper = require('./_helper');

var _extend = _.extend;

module.exports = function (config) {
  function Book(data) {
  }

  /**
   *
   * [distance] (number|string): distance radius in kilometers when number. Default 50km
   * */
  Book.findSome = function (text, limit) {
    var queryObj = _extend({
      body: {
          filter: {
            limit: { value: limit || 10 }
          }
      }
    }, baseBookData);

    queryObj.body.query = {
      match: {
        _all: {
          query: text,
          operator: "or"
        }
      }
    };

    return db.search(queryObj)
    .then(modelHelper.dbResultFromSearchToData);
  };

  var baseBookData = {
    index: 'books',
    type: 'book'
  };
  var db = config.db;
  return Book;
};
<|endoftext|>


<commit_before>import { DateTime, Interval } from "luxon";
import PropTypes from "prop-types";
import React from "react";
import styled from "styled-components";

import style from "@agir/front/genericComponents/_variables.scss";

import { Row } from "@agir/donations/donationForm/AllocationsWidget/Styles";
import { Column } from "@agir/front/genericComponents/grid";
import Card from "@agir/front/genericComponents/Card";
import { LayoutTitle } from "@agir/front/dashboardComponents/Layout";
import Button from "@agir/front/genericComponents/Button";
import EventCard from "@agir/front/genericComponents/EventCard";
import Link from "@agir/front/app/Link";

import { useSelector } from "@agir/front/globalContext/GlobalContext";
import {
  getIs2022,
  getIsSessionLoaded,
  getRoutes,
  getUser,
} from "@agir/front/globalContext/reducers";

import { dateFromISOString, displayHumanDay } from "@agir/lib/utils/time";
import FilterTabs from "@agir/front/genericComponents/FilterTabs";
import Onboarding from "@agir/front/genericComponents/Onboarding";
import useSWR from "swr";
import Skeleton from "@agir/front/genericComponents/Skeleton";
import { PageFadeIn } from "@agir/front/genericComponents/PageFadeIn";
import logger from "@agir/lib/utils/logger";

const log = logger(__filename);

const TopBar = styled.div`
  display: flex;
  flex-flow: row wrap;
  justify-content: space-between;
  margin: 0 0 25px;

  @media (max-width: ${style.collapse}px) {
    margin: 0 0 2rem;
  }

  & > ${LayoutTitle} {
    margin: 0;

    @media (max-width: ${style.collapse}px) {
      flex: 0 0 100%;
      margin-bottom: 1rem;
    }
  }

  & > div {
    display: flex;
    flex-direction: row-reverse;
    align-items: center;

    @media only screen and (max-width: ${style.collapse}px) {
      flex-direction: row;
      margin-left: 1.5rem;
      margin-right: 1.5rem;
    }
  }

  & ${Button} + ${Button} {
    @media only screen and (min-width: ${style.collapse}px) {
      margin-right: 0.5rem;
    }
    @media only screen and (max-width: ${style.collapse}px) {
      margin-left: 0.5rem;
    }
  }
`;

const Day = styled.h3`
  color: ${style.black500};
  text-transform: uppercase;
  font-size: 14px;
  margin-top: 24px;
`;

const EmptyAgenda = styled.div`
  & p {
    strong {
      color: ${style.black1000};
    }
    a {
      font-weight: bold;
      cursor: pointer;
    }
  }
`;

const StyledAgenda = styled.div`
  & header {
    margin-bottom: 0;
  }

  & h2 {
    font-size: 18px;
    font-weight: 500;
  }

  & h2,
  & ${Day}, & ${EmptyAgenda} {
    margin: 2rem 0 1rem;

    @media (max-width: ${style.collapse}px) {
      margin: 2rem 25px 1rem;
    }
  }

  & ${Card} + ${Card} {
    margin-top: 1rem;
  }
`;

const otherEventConfig = {
  NEAR_TYPE: {
    label: "À proximité",
    allowEmpty: true,
    filter: (events) =>
      events.filter(
        (event) =>
          event.distance &&
          event.distance < 100 * 1000 &&
          !event.rsvp &&
          dateFromISOString(event.endTime) > DateTime.local()
      ),
  },
  GROUPS_TYPE: {
    label: "Dans mes groupes",
    allowEmpty: (user) =>
      user && Array.isArray(user.groups) && user.groups.length > 0,
    filter: (events) =>
      events.filter(
        (event) =>
          Array.isArray(event.groups) &&
          dateFromISOString(event.endTime) > DateTime.local() &&
          event.groups.some((group) => !!group.isMember)
      ),
  },
  PAST_TYPE: {
    label: "Passés",
    allowEmpty: false,
    filter: (events) =>
      events
        .filter((event) => dateFromISOString(event.endTime) < DateTime.local())
        .reverse(),
  },
  ORGANIZED_TYPE: {
    label: "Organisés",
    allowEmpty: false,
    filter: (events) => events.filter((event) => event.isOrganizer).reverse(),
  },
};

const SuggestionsEvents = ({ suggestions }) => {
  log.debug("Suggested events ", suggestions);
  const routes = useSelector(getRoutes);
  const user = useSelector(getUser);

  const events = React.useMemo(
    () =>
      suggestions.map((event) => ({
        ...event,
        schedule: Interval.fromDateTimes(
          dateFromISOString(event.startTime),
          dateFromISOString(event.endTime)
        ),
      })),
    [suggestions]
  );
  const byType = React.useMemo(
    () =>
      Object.entries(otherEventConfig).reduce(
        (result, [typeKey, typeConfig]) => ({
          ...result,
          [typeKey]: typeConfig.filter(events),
        }),
        {}
      ),
    [events]
  );
  const types = React.useMemo(
    () =>
      Object.keys(byType).filter((type) => {
        if (byType[type].length > 0) {
          return true;
        }
        if (typeof otherEventConfig[type].allowEmpty === "function") {
          return otherEventConfig[type].allowEmpty(user);
        }
        return otherEventConfig[type].allowEmpty;
      }),
    [byType, user]
  );
  const tabs = React.useMemo(
    () => types.map((type) => otherEventConfig[type].label),
    [types]
  );

  const [activeType, setActiveType] = React.useState(types[0]);
  const updateFilter = React.useCallback(
    (i) => {
      setActiveType(types[i] || types[0]);
    },
    [types]
  );

  const activeTypeEvents = React.useMemo(
    () =>
      Object.entries(
        byType[activeType]
          ? byType[activeType].reduce((days, event) => {
              const day = displayHumanDay(dateFromISOString(event.startTime));
              (days[day] = days[day] || []).push(event);
              return days;
            }, {})
          : {}
      ),
    [byType, activeType]
  );

  return (
    <>
      <FilterTabs tabs={tabs} onTabChange={updateFilter} />
      {activeTypeEvents.length === 0 ? (
        <EmptyAgenda>
          {activeType === "NEAR_TYPE" && routes.personalInformation ? (

              Zut ! Il n'y a pas d'événement prévu à proximité ?{" "}

                Vérifiez votre adresse et code postal

              .

          ) : (

              Pas d'événement prévu dans votre ville ?{" "}
              <Link route="createEvent">Commencez par en créer un</Link>.

          )}
        </EmptyAgenda>
      ) : (
        activeTypeEvents.map(([date, events]) => (

            <Day>{date}</Day>
            {events.map((event) => (
              <EventCard key={event.id} {...event} />
            ))}

        ))
      )}
    </>
  );
};

SuggestionsEvents.propTypes = {
  suggestions: PropTypes.arrayOf(PropTypes.object),
};

const Agenda = () => {
  const routes = useSelector(getRoutes);
  const is2022 = useSelector(getIs2022);
  const isSessionLoaded = useSelector(getIsSessionLoaded);

  const { data: rsvped } = useSWR("/api/evenements/rsvped/");
  const { data: suggestions } = useSWR("/api/evenements/suggestions/");

  const rsvpedEvents = React.useMemo(
    () =>
      Array.isArray(rsvped)
        ? rsvped.map((event) => ({
            ...event,
            schedule: Interval.fromDateTimes(
              DateTime.fromISO(event.startTime).setLocale("fr"),
              DateTime.fromISO(event.endTime).setLocale("fr")
            ),
          }))
        : [],
    [rsvped]
  );

  return (

  );
};
export default Agenda;

Agenda.propTypes = {
  rsvped: PropTypes.arrayOf(
    PropTypes.shape({
      id: PropTypes.string,
      startTime: PropTypes.string,
      endTime: PropTypes.string,
    })
  ),
  suggestions: PropTypes.arrayOf(
    PropTypes.shape({
      id: PropTypes.string,
      startTime: PropTypes.string,
      endTime: PropTypes.string,
    })
  ),
};
<commit_msg>fix: avoid calling agenda page endpoints if user is unauthenticated<commit_after>import { DateTime, Interval } from "luxon";
import PropTypes from "prop-types";
import React, { useCallback } from "react";
import styled from "styled-components";

import style from "@agir/front/genericComponents/_variables.scss";

import { Row } from "@agir/donations/donationForm/AllocationsWidget/Styles";
import { Column } from "@agir/front/genericComponents/grid";
import Card from "@agir/front/genericComponents/Card";
import { LayoutTitle } from "@agir/front/dashboardComponents/Layout";
import Button from "@agir/front/genericComponents/Button";
import EventCard from "@agir/front/genericComponents/EventCard";
import Link from "@agir/front/app/Link";

import { useSelector } from "@agir/front/globalContext/GlobalContext";
import {
  getIs2022,
  getIsSessionLoaded,
  getRoutes,
  getUser,
} from "@agir/front/globalContext/reducers";

import { dateFromISOString, displayHumanDay } from "@agir/lib/utils/time";
import FilterTabs from "@agir/front/genericComponents/FilterTabs";
import Onboarding from "@agir/front/genericComponents/Onboarding";
import useSWR from "swr";
import Skeleton from "@agir/front/genericComponents/Skeleton";
import { PageFadeIn } from "@agir/front/genericComponents/PageFadeIn";
import logger from "@agir/lib/utils/logger";

const log = logger(__filename);

const TopBar = styled.div`
  display: flex;
  flex-flow: row wrap;
  justify-content: space-between;
  margin: 0 0 25px;

  @media (max-width: ${style.collapse}px) {
    margin: 0 0 2rem;
  }

  & > ${LayoutTitle} {
    margin: 0;

    @media (max-width: ${style.collapse}px) {
      flex: 0 0 100%;
      margin-bottom: 1rem;
    }
  }

  & > div {
    display: flex;
    flex-direction: row-reverse;
    align-items: center;

    @media only screen and (max-width: ${style.collapse}px) {
      flex-direction: row;
      margin-left: 1.5rem;
      margin-right: 1.5rem;
    }
  }

  & ${Button} + ${Button} {
    @media only screen and (min-width: ${style.collapse}px) {
      margin-right: 0.5rem;
    }
    @media only screen and (max-width: ${style.collapse}px) {
      margin-left: 0.5rem;
    }
  }
`;

const Day = styled.h3`
  color: ${style.black500};
  text-transform: uppercase;
  font-size: 14px;
  margin-top: 24px;
`;

const EmptyAgenda = styled.div`
  & p {
    strong {
      color: ${style.black1000};
    }
    a {
      font-weight: bold;
      cursor: pointer;
    }
  }
`;

const StyledAgenda = styled.div`
  & header {
    margin-bottom: 0;
  }

  & h2 {
    font-size: 18px;
    font-weight: 500;
  }

  & h2,
  & ${Day}, & ${EmptyAgenda} {
    margin: 2rem 0 1rem;

    @media (max-width: ${style.collapse}px) {
      margin: 2rem 25px 1rem;
    }
  }

  & ${Card} + ${Card} {
    margin-top: 1rem;
  }
`;

const otherEventConfig = {
  NEAR_TYPE: {
    label: "À proximité",
    allowEmpty: true,
    filter: (events) =>
      events.filter(
        (event) =>
          event.distance &&
          event.distance < 100 * 1000 &&
          !event.rsvp &&
          dateFromISOString(event.endTime) > DateTime.local()
      ),
  },
  GROUPS_TYPE: {
    label: "Dans mes groupes",
    allowEmpty: (user) =>
      user && Array.isArray(user.groups) && user.groups.length > 0,
    filter: (events) =>
      events.filter(
        (event) =>
          Array.isArray(event.groups) &&
          dateFromISOString(event.endTime) > DateTime.local() &&
          event.groups.some((group) => !!group.isMember)
      ),
  },
  PAST_TYPE: {
    label: "Passés",
    allowEmpty: false,
    filter: (events) =>
      events
        .filter((event) => dateFromISOString(event.endTime) < DateTime.local())
        .reverse(),
  },
  ORGANIZED_TYPE: {
    label: "Organisés",
    allowEmpty: false,
    filter: (events) => events.filter((event) => event.isOrganizer).reverse(),
  },
};

const SuggestionsEvents = ({ suggestions }) => {
  log.debug("Suggested events ", suggestions);
  const routes = useSelector(getRoutes);
  const user = useSelector(getUser);

  const events = React.useMemo(
    () =>
      Array.isArray(suggestions)
        ? suggestions.map((event) => ({
            ...event,
            schedule: Interval.fromDateTimes(
              dateFromISOString(event.startTime),
              dateFromISOString(event.endTime)
            ),
          }))
        : [],
    [suggestions]
  );
  const byType = React.useMemo(
    () =>
      Object.entries(otherEventConfig).reduce(
        (result, [typeKey, typeConfig]) => ({
          ...result,
          [typeKey]: typeConfig.filter(events),
        }),
        {}
      ),
    [events]
  );
  const types = React.useMemo(
    () =>
      Object.keys(byType).filter((type) => {
        if (byType[type].length > 0) {
          return true;
        }
        if (typeof otherEventConfig[type].allowEmpty === "function") {
          return otherEventConfig[type].allowEmpty(user);
        }
        return otherEventConfig[type].allowEmpty;
      }),
    [byType, user]
  );
  const tabs = React.useMemo(
    () => types.map((type) => otherEventConfig[type].label),
    [types]
  );

  const [activeType, setActiveType] = React.useState(types[0]);
  const updateFilter = React.useCallback(
    (i) => {
      setActiveType(types[i] || types[0]);
    },
    [types]
  );

  const activeTypeEvents = React.useMemo(
    () =>
      Object.entries(
        byType[activeType]
          ? byType[activeType].reduce((days, event) => {
              const day = displayHumanDay(dateFromISOString(event.startTime));
              (days[day] = days[day] || []).push(event);
              return days;
            }, {})
          : {}
      ),
    [byType, activeType]
  );

  return (
    <>
      <FilterTabs tabs={tabs} onTabChange={updateFilter} />
      {activeTypeEvents.length === 0 ? (
        <EmptyAgenda>
          {activeType === "NEAR_TYPE" && routes.personalInformation ? (

              Zut ! Il n'y a pas d'événement prévu à proximité ?{" "}

                Vérifiez votre adresse et code postal

              .

          ) : (

              Pas d'événement prévu dans votre ville ?{" "}
              <Link route="createEvent">Commencez par en créer un</Link>.

          )}
        </EmptyAgenda>
      ) : (
        activeTypeEvents.map(([date, events]) => (

            <Day>{date}</Day>
            {events.map((event) => (
              <EventCard key={event.id} {...event} />
            ))}

        ))
      )}
    </>
  );
};

SuggestionsEvents.propTypes = {
  suggestions: PropTypes.arrayOf(PropTypes.object),
};

const Agenda = () => {
  const routes = useSelector(getRoutes);
  const is2022 = useSelector(getIs2022);
  const isSessionLoaded = useSelector(getIsSessionLoaded);
  const user = useSelector(getUser);

  const isPaused = useCallback(() => {
    return !user;
  }, [user]);

  const { data: rsvped } = useSWR("/api/evenements/rsvped/", {
    isPaused,
  });
  const { data: suggestions } = useSWR("/api/evenements/suggestions/", {
    isPaused,
  });

  const rsvpedEvents = React.useMemo(
    () =>
      Array.isArray(rsvped)
        ? rsvped.map((event) => ({
            ...event,
            schedule: Interval.fromDateTimes(
              DateTime.fromISO(event.startTime).setLocale("fr"),
              DateTime.fromISO(event.endTime).setLocale("fr")
            ),
          }))
        : [],
    [rsvped]
  );

  return (

  );
};
export default Agenda;

Agenda.propTypes = {
  rsvped: PropTypes.arrayOf(
    PropTypes.shape({
      id: PropTypes.string,
      startTime: PropTypes.string,
      endTime: PropTypes.string,
    })
  ),
  suggestions: PropTypes.arrayOf(
    PropTypes.shape({
      id: PropTypes.string,
      startTime: PropTypes.string,
      endTime: PropTypes.string,
    })
  ),
};
<|endoftext|>


<commit_before>define(function (require) {

  var Utils = require('./Utils');
      Router = require('../Router'),
      Constants = require('constants/QuotaRequestConstants'),
      QuotaRequest = require('models/QuotaRequest');

  return {
      update: function(params) {
        var request = params.request,
            response = params.response,
            quota = params.quota,
            status = params.status;

        var newAttributes = {
          admin_message: response,
          quota: quota,
          status: status
        };

        request.set(newAttributes);
        Router.getInstance().transitionTo("admin");
        request.save(newAttributes, {patch: true}).done(function() {
          Utils.dispatch(Constants.UPDATE, {model: request});
          Utils.dispatch(Constants.REMOVE, {model: request});
        });
      }
  };

});
<commit_msg>explicitly declare variables<commit_after>define(function (require) {

  var Utils = require('./Utils'),
      Router = require('../Router'),
      Constants = require('constants/QuotaRequestConstants'),
      QuotaRequest = require('models/QuotaRequest');

  return {
      update: function(params) {
        var request = params.request,
            response = params.response,
            quota = params.quota,
            status = params.status;

        var newAttributes = {
          admin_message: response,
          quota: quota,
          status: status
        };

        request.set(newAttributes);
        Router.getInstance().transitionTo("admin");
        request.save(newAttributes, {patch: true}).done(function() {
          Utils.dispatch(Constants.UPDATE, {model: request});
          Utils.dispatch(Constants.REMOVE, {model: request});
        });
      }
  };

});
<|endoftext|>


<commit_before>(function($) {
  $.fn.scroller = function () {
    var list = this;
    list.items = [];

    list.push = function(items) {
      items.css('display', 'none').highlight('tulip time').highlight('tech embassy');
      items.each(function() {
        list.items.push(this);
      })
    }

    list.cleanup = function() {
      if(list.children().length > 30) {
        list.children().slice(0, 15).remove()
      }
    }

    var process = function() {
      $(list.items.shift()).appendTo(list).slideDown(5000);
      list.cleanup();
    }

    setInterval(process, 5000);
    return list;
  }

  var query = encodeURIComponent('techembassy OR "tech embassy" OR ideafoundry OR Tulip_time OR "Tulip Time" -pella');

  $(function() {
    tweets = $('#tweets').scroller();
    flicks = $('#flickr').scroller();

    function fetchTweets() {
      if(tweets.items.length < 15) {
        // since_id
        var url = 'http://search.twitter.com/search.json?q=' + query + '&rpp=30&callback=?';
        $.getJSON(url, function(data) {
          $.each(data.results, function() {
            tweets.push($('
' + this.from_user + ': ' + this.text + '
'))
           });
         });
      }
      setTimeout(fetchTweets, 5000);
    }

    jsonFlickrApi = function(data) {
      $.each(data.photos.photo, function(i,photo){
        //notice that "t.jpg" is where you change the
        //size of the image
        var t_url = "http://farm" + photo.farm +
        ".static.flickr.com/" + photo.server + "/" +
        photo.id + "_" + photo.secret + "_" + "m.jpg";

        var p_url = "http://www.flickr.com/photos/" +
        photo.owner + "/" + photo.id;

        flicks.push($("").attr("src", t_url).attr("class", 'flickr').wrap("

"));
      });
    }
    function fetchFlicks() {
      if (flicks.items.length < 15) {
          $.getJSON("http://api.flickr.com/services/rest/?callback=?&format=json&method=flickr.photos.search&text=%22tulip%20time%22%20OR%20%22tech%20embassy%22&tag_mode=all&api_key=f9eed8709bd8c9663f988960cbdad53f&jsoncallback=jsonFlickrApi")
      }
      window.setTimeout(fetchFlicks, 120000);
    }

    fetchTweets();
    fetchFlicks();
  });

})(jQuery)

    // window.setInterval(showNext, 7000, '#tweets')
    // window.setInterval(showNext, 4000, '#flickr')
    // function moveit(element) {
    //   var top = $(element).position().top - 100;
    //   $(element).animate({top: top + 'px'}, {duration:5000, easing:'linear',
    //     complete: function() { moveit(element) }});
    // }
    // moveit('#tweets');
<commit_msg>More highlights<commit_after>(function($) {
  $.fn.scroller = function () {
    var list = this;
    list.items = [];

    list.push = function(items) {
      items.css('display', 'none').highlight('tulip time').highlight('tuliptime').highlight('tulip_time').highlight('tech embassy')highlight('techembassy');
      items.each(function() {
        list.items.push(this);
      })
    }

    list.cleanup = function() {
      if(list.children().length > 30) {
        list.children().slice(0, 15).remove()
      }
    }

    var process = function() {
      $(list.items.shift()).appendTo(list).slideDown(5000);
      list.cleanup();
    }

    setInterval(process, 5000);
    return list;
  }

  var query = encodeURIComponent('techembassy OR "tech embassy" OR ideafoundry OR Tulip_time OR "Tulip Time" -pella');

  $(function() {
    tweets = $('#tweets').scroller();
    flicks = $('#flickr').scroller();

    function fetchTweets() {
      if(tweets.items.length < 15) {
        // since_id
        var url = 'http://search.twitter.com/search.json?q=' + query + '&rpp=30&callback=?';
        $.getJSON(url, function(data) {
          $.each(data.results, function() {
            tweets.push($('
' + this.from_user + ': ' + this.text + '
'))
           });
         });
      }
      setTimeout(fetchTweets, 5000);
    }

    jsonFlickrApi = function(data) {
      $.each(data.photos.photo, function(i,photo){
        //notice that "t.jpg" is where you change the
        //size of the image
        var t_url = "http://farm" + photo.farm +
        ".static.flickr.com/" + photo.server + "/" +
        photo.id + "_" + photo.secret + "_" + "m.jpg";

        var p_url = "http://www.flickr.com/photos/" +
        photo.owner + "/" + photo.id;

        flicks.push($("").attr("src", t_url).attr("class", 'flickr').wrap("

"));
      });
    }
    function fetchFlicks() {
      if (flicks.items.length < 15) {
          $.getJSON("http://api.flickr.com/services/rest/?callback=?&format=json&method=flickr.photos.search&text=%22tulip%20time%22%20OR%20%22tech%20embassy%22&tag_mode=all&api_key=f9eed8709bd8c9663f988960cbdad53f&jsoncallback=jsonFlickrApi")
      }
      window.setTimeout(fetchFlicks, 120000);
    }

    fetchTweets();
    fetchFlicks();
  });

})(jQuery)

    // window.setInterval(showNext, 7000, '#tweets')
    // window.setInterval(showNext, 4000, '#flickr')
    // function moveit(element) {
    //   var top = $(element).position().top - 100;
    //   $(element).animate({top: top + 'px'}, {duration:5000, easing:'linear',
    //     complete: function() { moveit(element) }});
    // }
    // moveit('#tweets');
<|endoftext|>


<commit_before>import React, { useReducer, useState, useEffect, useRef } from 'react';
import { includes } from 'lodash';
import { useHistory, useLocation } from 'react-router-dom';
import { Header } from '@buffetjs/custom';
import { useDebounce } from '@buffetjs/hooks';
import {
  HeaderSearch,
  PageFooter,
  useGlobalContext,
  generateFiltersFromSearch,
  generateSearchFromFilters,
  request,
  useQuery,
} from 'strapi-helper-plugin';

import { getRequestUrl, getTrad } from '../../utils';

import Container from '../../components/Container';
import ControlsWrapper from '../../components/ControlsWrapper';
import SelectAll from '../../components/SelectAll';
import SortPicker from '../../components/SortPicker';
import Filters from '../../components/Filters';
import List from '../../components/List';
import ListEmpty from '../../components/ListEmpty';
import ModalStepper from '../ModalStepper';
import {
  deleteFilters,
  generatePageFromStart,
  generateStartFromPage,
  getHeaderLabel,
} from './utils';
import init from './init';
import reducer, { initialState } from './reducer';

const HomePage = () => {
  const { formatMessage } = useGlobalContext();
  const [reducerState, dispatch] = useReducer(reducer, initialState, init);
  const query = useQuery();
  const [isOpen, setIsOpen] = useState(false);
  const [searchValue, setSearchValue] = useState(query.get('_q') || '');
  const { push } = useHistory();
  const { search } = useLocation();
  const isMounted = useRef();

  const { data, dataCount, dataToDelete } = reducerState.toJS();
  const pluginName = formatMessage({ id: getTrad('plugin.name') });
  const paramsKeys = ['_limit', '_start', '_q', '_sort'];
  const debouncedSearch = useDebounce(searchValue, 300);

  useEffect(() => {
    fetchDataCount();
  }, []);

  useEffect(() => {
    handleChangeParams({ target: { name: '_q', value: searchValue } });
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [debouncedSearch]);

  useEffect(() => {
    isMounted.current = true;
    fetchData();

    return () => {
      isMounted.current = false;
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [search]);

  const deleteMedia = async id => {
    const requestURL = getRequestUrl(`files/${id}`);

    try {
      await request(requestURL, {
        method: 'DELETE',
      });
    } catch (err) {
      if (isMounted.current) {
        strapi.notification.error('notification.error');
      }
    }
  };

  const fetchData = async () => {
    const requestURL = getRequestUrl('files');

    try {
      const data = await request(`${requestURL}${search}`, {
        method: 'GET',
      });

      if (isMounted.current) {
        dispatch({
          type: 'GET_DATA_SUCCEEDED',
          data,
        });
      }
    } catch (err) {
      if (isMounted.current) {
        strapi.notification.error('notification.error');
      }
    }
  };

  const fetchDataCount = async () => {
    const requestURL = getRequestUrl('files/count');

    try {
      const { count } = await request(requestURL, {
        method: 'GET',
      });

      if (isMounted.current) {
        dispatch({
          type: 'GET_DATA_COUNT_SUCCEEDED',
          count,
        });
      }
    } catch (err) {
      if (isMounted.current) {
        strapi.notification.error('notification.error');
      }
    }
  };

  const getSearchParams = () => {
    const params = {};

    query.forEach((value, key) => {
      if (includes(paramsKeys, key)) {
        params[key] = value;
      }
    });

    return params;
  };

  const generateNewSearch = updatedParams => {
    return {
      ...getSearchParams(),
      filters: generateFiltersFromSearch(search),
      ...updatedParams,
    };
  };

  const handleChangeCheck = ({ target: { name, value } }) => {
    dispatch({
      type: 'ON_CHANGE_DATA_TO_DELETE',
      id: parseInt(name, 10),
      value,
    });
  };

  const handleChangeListParams = ({ target: { name, value } }) => {
    if (name.includes('_page')) {
      handleChangeParams({
        target: { name: '_start', value: generateStartFromPage(value, limit) },
      });
    } else {
      handleChangeParams({ target: { name: '_limit', value } });
    }
  };

  const handleChangeParams = ({ target: { name, value } }) => {
    const updatedQueryParams = generateNewSearch({ [name]: value });
    const newSearch = generateSearchFromFilters(updatedQueryParams);

    push({ search: encodeURI(newSearch) });
  };

  const handleChangeSearchValue = ({ target: { value } }) => {
    setSearchValue(value);
  };

  const handleClearSearch = () => {
    setSearchValue('');
  };

  const handleClickToggleModal = (refetch = false) => {
    setIsOpen(prev => !prev);

    if (refetch) {
      fetchData();
      fetchDataCount();
    }
  };

  const handleDeleteFilter = filter => {
    const currentFilters = generateFiltersFromSearch(search);
    const updatedFilters = deleteFilters(currentFilters, filter);

    handleChangeParams({
      target: { name: 'filters', value: updatedFilters },
    });
  };

  const handleDeleteMedias = async () => {
    await Promise.all(dataToDelete.map(item => deleteMedia(item.id)));

    dispatch({
      type: 'CLEAR_DATA_TO_DELETE',
    });

    fetchData();
    fetchDataCount();
  };

  const handleSelectAll = () => {
    dispatch({
      type: 'TOGGLE_SELECT_ALL',
    });
  };

  const headerProps = {
    title: {
      label: pluginName,
    },
    content: formatMessage(
      {
        id: getTrad(getHeaderLabel(data)),
      },
      { number: dataCount }
    ),
    actions: [
      {
        disabled: dataToDelete.length === 0,
        color: 'cancel',
        // TradId from the strapi-admin package
        label: formatMessage({ id: 'app.utils.delete' }),
        onClick: handleDeleteMedias,
        type: 'button',
      },
      {
        disabled: false,
        color: 'primary',
        label: formatMessage({ id: getTrad('header.actions.upload-assets') }),
        onClick: () => handleClickToggleModal(),
        type: 'button',
      },
    ],
  };

  const limit = parseInt(query.get('_limit'), 10) || 10;
  const start = parseInt(query.get('_start'), 10) || 0;

  const params = {
    _limit: parseInt(query.get('_limit'), 10) || 10,
    _page: generatePageFromStart(start, limit),
  };

  const paginationCount = data.length < limit ? data.length : dataCount;

  const hasSomeCheckboxSelected = data.some(item =>
    dataToDelete.find(itemToDelete => item.id === itemToDelete.id)
  );

  const areAllCheckboxesSelected =
    data.every(item => dataToDelete.find(itemToDelete => item.id === itemToDelete.id)) &&
    hasSomeCheckboxSelected;

  const selectedItems = dataToDelete.map(item => item.id);

  return (
    <Container>
      <Header {...headerProps} />
      <HeaderSearch
        label={pluginName}
        onChange={handleChangeSearchValue}
        onClear={handleClearSearch}
        placeholder={formatMessage({ id: getTrad('search.placeholder') })}
        name="_q"
        value={searchValue}
      />
      <ControlsWrapper>
        <SelectAll
          onChange={handleSelectAll}
          checked={areAllCheckboxesSelected}
          someChecked={hasSomeCheckboxSelected && !areAllCheckboxesSelected}
        />
        <SortPicker onChange={handleChangeParams} value={query.get('_sort') || null} />
        <Filters
          onChange={handleChangeParams}
          filters={generateFiltersFromSearch(search)}
          onClick={handleDeleteFilter}
        />
      </ControlsWrapper>
      {dataCount > 0 ? (
        <>
          <List data={data} onChange={handleChangeCheck} selectedItems={selectedItems} />
          <PageFooter
            context={{ emitEvent: () => {} }}
            count={paginationCount}
            onChangeParams={handleChangeListParams}
            params={params}
          />
        </>
      ) : (
        <ListEmpty onClick={handleClickToggleModal} />
      )}
      <ModalStepper isOpen={isOpen} onToggle={handleClickToggleModal} />
    </Container>
  );
};

export default HomePage;
<commit_msg>confirm popup on delete<commit_after>import React, { useReducer, useState, useEffect, useRef } from 'react';
import { includes } from 'lodash';
import { useHistory, useLocation } from 'react-router-dom';
import { Header } from '@buffetjs/custom';
import { useDebounce } from '@buffetjs/hooks';
import {
  HeaderSearch,
  PageFooter,
  PopUpWarning,
  useGlobalContext,
  generateFiltersFromSearch,
  generateSearchFromFilters,
  request,
  useQuery,
} from 'strapi-helper-plugin';

import { getRequestUrl, getTrad } from '../../utils';

import Container from '../../components/Container';
import ControlsWrapper from '../../components/ControlsWrapper';
import SelectAll from '../../components/SelectAll';
import SortPicker from '../../components/SortPicker';
import Filters from '../../components/Filters';
import List from '../../components/List';
import ListEmpty from '../../components/ListEmpty';
import ModalStepper from '../ModalStepper';
import {
  deleteFilters,
  generatePageFromStart,
  generateStartFromPage,
  getHeaderLabel,
} from './utils';
import init from './init';
import reducer, { initialState } from './reducer';

const HomePage = () => {
  const { formatMessage } = useGlobalContext();
  const [reducerState, dispatch] = useReducer(reducer, initialState, init);
  const query = useQuery();
  const [modalIsOpen, setModalIsOpen] = useState(false);
  const [confirmPopupIsOpen, setConfirmPopupIsOpen] = useState(false);
  const [searchValue, setSearchValue] = useState(query.get('_q') || '');
  const { push } = useHistory();
  const { search } = useLocation();
  const isMounted = useRef();

  const { data, dataCount, dataToDelete } = reducerState.toJS();
  const pluginName = formatMessage({ id: getTrad('plugin.name') });
  const paramsKeys = ['_limit', '_start', '_q', '_sort'];
  const debouncedSearch = useDebounce(searchValue, 300);

  useEffect(() => {
    fetchDataCount();
  }, []);

  useEffect(() => {
    handleChangeParams({ target: { name: '_q', value: searchValue } });
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [debouncedSearch]);

  useEffect(() => {
    isMounted.current = true;
    fetchData();

    return () => {
      isMounted.current = false;
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [search]);

  const deleteMedia = async id => {
    const requestURL = getRequestUrl(`files/${id}`);

    try {
      await request(requestURL, {
        method: 'DELETE',
      });
    } catch (err) {
      if (isMounted.current) {
        strapi.notification.error('notification.error');
      }
    }
  };

  const fetchData = async () => {
    const requestURL = getRequestUrl('files');

    try {
      const data = await request(`${requestURL}${search}`, {
        method: 'GET',
      });

      if (isMounted.current) {
        dispatch({
          type: 'GET_DATA_SUCCEEDED',
          data,
        });
      }
    } catch (err) {
      if (isMounted.current) {
        strapi.notification.error('notification.error');
      }
    }
  };

  const fetchDataCount = async () => {
    const requestURL = getRequestUrl('files/count');

    try {
      const { count } = await request(requestURL, {
        method: 'GET',
      });

      if (isMounted.current) {
        dispatch({
          type: 'GET_DATA_COUNT_SUCCEEDED',
          count,
        });
      }
    } catch (err) {
      if (isMounted.current) {
        strapi.notification.error('notification.error');
      }
    }
  };

  const getSearchParams = () => {
    const params = {};

    query.forEach((value, key) => {
      if (includes(paramsKeys, key)) {
        params[key] = value;
      }
    });

    return params;
  };

  const generateNewSearch = updatedParams => {
    return {
      ...getSearchParams(),
      filters: generateFiltersFromSearch(search),
      ...updatedParams,
    };
  };

  const handleChangeCheck = ({ target: { name, value } }) => {
    dispatch({
      type: 'ON_CHANGE_DATA_TO_DELETE',
      id: parseInt(name, 10),
      value,
    });
  };

  const handleChangeListParams = ({ target: { name, value } }) => {
    if (name.includes('_page')) {
      handleChangeParams({
        target: { name: '_start', value: generateStartFromPage(value, limit) },
      });
    } else {
      handleChangeParams({ target: { name: '_limit', value } });
    }
  };

  const handleChangeParams = ({ target: { name, value } }) => {
    const updatedQueryParams = generateNewSearch({ [name]: value });
    const newSearch = generateSearchFromFilters(updatedQueryParams);

    push({ search: encodeURI(newSearch) });
  };

  const handleChangeSearchValue = ({ target: { value } }) => {
    setSearchValue(value);
  };

  const handleClearSearch = () => {
    setSearchValue('');
  };

  const handleClickToggleModal = (refetch = false) => {
    setModalIsOpen(prev => !prev);

    if (refetch) {
      fetchData();
      fetchDataCount();
    }
  };

  const handleClickTogglePopup = () => {
    setConfirmPopupIsOpen(prev => !prev);
  };

  const handleDeleteFilter = filter => {
    const currentFilters = generateFiltersFromSearch(search);
    const updatedFilters = deleteFilters(currentFilters, filter);

    handleChangeParams({
      target: { name: 'filters', value: updatedFilters },
    });
  };

  const handleDeleteMedias = async () => {
    await Promise.all(dataToDelete.map(item => deleteMedia(item.id)));

    dispatch({
      type: 'CLEAR_DATA_TO_DELETE',
    });

    setConfirmPopupIsOpen(false);
    fetchData();
    fetchDataCount();
  };

  const handleSelectAll = () => {
    dispatch({
      type: 'TOGGLE_SELECT_ALL',
    });
  };

  const headerProps = {
    title: {
      label: pluginName,
    },
    content: formatMessage(
      {
        id: getTrad(getHeaderLabel(data)),
      },
      { number: dataCount }
    ),
    actions: [
      {
        disabled: dataToDelete.length === 0,
        color: 'cancel',
        // TradId from the strapi-admin package
        label: formatMessage({ id: 'app.utils.delete' }),
        onClick: () => setConfirmPopupIsOpen(true),
        type: 'button',
      },
      {
        disabled: false,
        color: 'primary',
        label: formatMessage({ id: getTrad('header.actions.upload-assets') }),
        onClick: () => handleClickToggleModal(),
        type: 'button',
      },
    ],
  };

  const limit = parseInt(query.get('_limit'), 10) || 10;
  const start = parseInt(query.get('_start'), 10) || 0;

  const params = {
    _limit: parseInt(query.get('_limit'), 10) || 10,
    _page: generatePageFromStart(start, limit),
  };

  const paginationCount = data.length < limit ? data.length : dataCount;

  const hasSomeCheckboxSelected = data.some(item =>
    dataToDelete.find(itemToDelete => item.id === itemToDelete.id)
  );

  const areAllCheckboxesSelected =
    data.every(item => dataToDelete.find(itemToDelete => item.id === itemToDelete.id)) &&
    hasSomeCheckboxSelected;

  const selectedItems = dataToDelete.map(item => item.id);

  return (
    <Container>
      <Header {...headerProps} />
      <HeaderSearch
        label={pluginName}
        onChange={handleChangeSearchValue}
        onClear={handleClearSearch}
        placeholder={formatMessage({ id: getTrad('search.placeholder') })}
        name="_q"
        value={searchValue}
      />
      <ControlsWrapper>
        <SelectAll
          onChange={handleSelectAll}
          checked={areAllCheckboxesSelected}
          someChecked={hasSomeCheckboxSelected && !areAllCheckboxesSelected}
        />
        <SortPicker onChange={handleChangeParams} value={query.get('_sort') || null} />
        <Filters
          onChange={handleChangeParams}
          filters={generateFiltersFromSearch(search)}
          onClick={handleDeleteFilter}
        />
      </ControlsWrapper>
      {dataCount > 0 ? (
        <>
          <List data={data} onChange={handleChangeCheck} selectedItems={selectedItems} />
          <PageFooter
            context={{ emitEvent: () => {} }}
            count={paginationCount}
            onChangeParams={handleChangeListParams}
            params={params}
          />
        </>
      ) : (
        <ListEmpty onClick={handleClickToggleModal} />
      )}
      <ModalStepper isOpen={modalIsOpen} onToggle={handleClickToggleModal} />
      <PopUpWarning
        isOpen={confirmPopupIsOpen}
        toggleModal={handleClickTogglePopup}
        popUpWarningType="danger"
        onConfirm={handleDeleteMedias}
      />
    </Container>
  );
};

export default HomePage;
<|endoftext|>


<commit_before>/*!
 * relike <https://github.com/hybridables/relike>
 *
 * Copyright (c) 2016 Charlike Mike Reagent <@tunnckoCore> (http://www.tunnckocore.tk)
 * Released under the MIT license.
 */

'use strict'

var fs = require('fs')
var test = require('mukla')
var isArray = require('isarray')
var isBuffer = require('is-buffer')
var semver = require('semver')
var relike = require('./index')

function create () {
  return require('./index')
}

function noop () {}

function notSkipOne (one, two, cb) {
  cb(null, one, two, noop)
}

function notSkipTwo (one, two, cb) {
  cb(null, one, two, fs.readFileSync)
}

function multipleArgs (one, two, three, cb) {
  cb(null, one, two, three)
}

test('should .catch TypeError if not function given', function () {
  return relike(123).catch(function (err) {
    test.strictEqual(err.name, 'TypeError')
    test.ok(/expect `fn` be function/.test(err.message))
  })
})

test('should promisify with native Promise or Bluebird', function () {
  var promise = relike(fs.readFile, './package.json', 'utf-8')

  return promise.then(function (res) {
    test.ok(res.indexOf('"license": "MIT"') !== -1)
    if (semver.lt(process.version, '0.11.13')) {
      test.ok(promise.Promise.___bluebirdPromise === true)
      test.ok(promise.___bluebirdPromise, true)
    }
  })
})

test('should flatten multiple arguments to array by default', function () {
  return relike(multipleArgs, 11, 22, 33).then(function (res) {
    test.strictEqual(isArray(res), true)
    test.deepEqual(res, [11, 22, 33])
  })
})

test('should skip last argument only if it is `fn(foo, bar, cb)` (async fn)', function () {
  return relike(notSkipOne, 111, 222).then(function (res) {
    test.strictEqual(isArray(res), true)
    test.deepEqual(res, [111, 222, noop])
  })
})

test('should not skip last argument and work core api (fs.readFileSync)', function () {
  return relike(notSkipTwo, 333, 5555).then(function (res) {
    test.strictEqual(isArray(res), true)
    test.deepEqual(res, [333, 5555, fs.readFileSync])
  })
})

test('should not skip if pass callback fn, e.g. fn(err, res) as last argument', function () {
  function foo (_err, res) {}
  return relike(function (one, fn, cb) {
    cb(null, one, fn)
  }, 123, foo).then(function (res) {
    test.strictEqual(isArray(res), true)
    test.deepEqual(res, [123, foo])
  })
})

test('should promisify sync function `fs.readFileSync` and handle utf8 result', function () {
  var promise = relike(fs.readFileSync, 'package.json', 'utf8')

  return promise
    .then(JSON.parse)
    .then(function (res) {
      test.strictEqual(res.name, 'relike')
    })
})

test('should promisify `fs.readFileSync` and handle buffer result', function () {
  return relike(fs.readFileSync, 'package.json').then(function (buf) {
    test.strictEqual(isBuffer(buf), true)
  })
})

test('should catch errors from failing sync function', function () {
  var promise = relike(fs.readFileSync, 'foobar.json', 'utf8')

  return promise.catch(function (err) {
    test.strictEqual(err.code, 'ENOENT')
    test.strictEqual(/no such file or directory/.test(err.message), true)
  })
})

test('should `.promisify` method wrap a function and return a function', function () {
  var readFile = relike.promisify(fs.readFile)

  return readFile('package.json', 'utf8')
    .then(JSON.parse)
    .then(function (data) {
      test.strictEqual(data.name, 'relike')
    })
})

test('should `.promisify` method allow passing `.Promise` to promisified function', function () {
  var relike = create()
  var readFile = relike.promisify(fs.readFile)
  readFile.Promise = require('pinkie') // eslint-disable-line
  var promise = readFile('package.json', 'utf8')

  return promise
    .then(function (res) {
      test.strictEqual(typeof res, 'string')
      test.strictEqual(isBuffer(res), false)
      if (semver.lt(process.version, '0.11.13')) {
        test.strictEqual(promise.___customPromise, true)
        test.strictEqual(promise.Promise.___customPromise, true)
      }
    })
})

test('should use promise passed to `relike.promisify.Promise` and promisifing with `.promisify`', function () {
  var relike = create()
  relike.promisify.Promise = require('pinkie') // eslint-disable-line
  var statFile = relike.promisify(fs.stat)
  var promise = statFile('index.js')

  return promise.then(function (res) {
    if (semver.lt(process.version, '0.11.13')) {
      test.ok(promise.___customPromise === true)
    }
    test.strictEqual(typeof res, 'object')
    test.ok(res.mtime)
  })
})

test('should not use custom promise constructor passed to `relike.Promise` when use `.promisify`', function () {
  var relike = create()
  relike.Promise = require('pinkie') // eslint-disable-line
  var readSync = relike.promisify(fs.readFileSync)
  var promise = readSync('README.md', 'utf8')

  return promise.then(function resolve (result) {
    test.ok(typeof result === 'string')
    if (semver.lt(process.version, '0.11.13')) {
      test.strictEqual(promise.___customPromise, true)
    }
  })
})

test('should promisify with promise module (pinkie) given in `relike.Promise`', function () {
  var relike = create()
  relike.Promise = require('pinkie') // eslint-disable-line
  var promise = relike(fs.readFile, 'package.json')

  return promise.then(function (res) {
    test.strictEqual(isBuffer(res), true)
    if (semver.lt(process.version, '0.11.13')) {
      test.strictEqual(promise.___customPromise, true)
      test.strictEqual(promise.Promise.___customPromise, true)
    }
  })
})
<commit_msg>add more tests<commit_after>/*!
 * relike <https://github.com/hybridables/relike>
 *
 * Copyright (c) 2016 Charlike Mike Reagent <@tunnckoCore> (http://www.tunnckocore.tk)
 * Released under the MIT license.
 */

'use strict'

var fs = require('fs')
var test = require('mukla')
var isArray = require('isarray')
var isBuffer = require('is-buffer')
var semver = require('semver')
var relike = require('./index')

function create () {
  return require('./index')
}

function noop () {}

function notSkipOne (one, two, cb) {
  cb(null, one, two, noop)
}

function notSkipTwo (one, two, cb) {
  cb(null, one, two, fs.readFileSync)
}

function multipleArgs (one, two, three, cb) {
  cb(null, one, two, three)
}

test('should .catch TypeError if not function given', function () {
  return relike(123).catch(function (err) {
    test.strictEqual(err.name, 'TypeError')
    test.ok(/expect `fn` be function/.test(err.message))
  })
})

test('should promisify with native Promise or Bluebird', function () {
  var promise = relike(fs.readFile, './package.json', 'utf-8')

  return promise.then(function (res) {
    test.ok(res.indexOf('"license": "MIT"') !== -1)
    if (semver.lt(process.version, '0.11.13')) {
      test.ok(promise.Promise.___bluebirdPromise === true)
      test.ok(promise.___bluebirdPromise, true)
    }
  })
})

test('should flatten multiple arguments to array by default', function () {
  return relike(multipleArgs, 11, 22, 33).then(function (res) {
    test.strictEqual(isArray(res), true)
    test.deepEqual(res, [11, 22, 33])
  })
})

test('should skip last argument only if it is `fn(foo, bar, cb)` (async fn)', function () {
  return relike(notSkipOne, 111, 222).then(function (res) {
    test.strictEqual(isArray(res), true)
    test.deepEqual(res, [111, 222, noop])
  })
})

test('should not skip last argument and work core api (fs.readFileSync)', function () {
  return relike(notSkipTwo, 333, 5555).then(function (res) {
    test.strictEqual(isArray(res), true)
    test.deepEqual(res, [333, 5555, fs.readFileSync])
  })
})

test('should not skip if pass callback fn, e.g. fn(err, res) as last argument', function () {
  function foo (_err, res) {}
  return relike(function (one, fn, cb) {
    cb(null, one, fn)
  }, 123, foo).then(function (res) {
    test.strictEqual(isArray(res), true)
    test.deepEqual(res, [123, foo])
  })
})

test('should promisify sync function `fs.readFileSync` and handle utf8 result', function () {
  var promise = relike(fs.readFileSync, 'package.json', 'utf8')

  return promise
    .then(JSON.parse)
    .then(function (res) {
      test.strictEqual(res.name, 'relike')
    })
})

test('should promisify `fs.readFileSync` and handle buffer result', function () {
  return relike(fs.readFileSync, 'package.json').then(function (buf) {
    test.strictEqual(isBuffer(buf), true)
  })
})

test('should catch errors from failing sync function', function () {
  var promise = relike(fs.readFileSync, 'foobar.json', 'utf8')

  return promise.catch(function (err) {
    test.strictEqual(err.code, 'ENOENT')
    test.strictEqual(/no such file or directory/.test(err.message), true)
  })
})

test('should mute all errors and `.catch` them (should not crash)', function (done) {
  return relike(function () {
    foobar // eslint-disable-line no-undef
    return 123
  }).catch(function (err) {
    test.ifError(!err)
    test.ok(err instanceof Error)
    test.equal(err.name, 'ReferenceError')
  })
})

test('should `.promisify` method wrap a function and return a function', function () {
  var readFile = relike.promisify(fs.readFile)

  return readFile('package.json', 'utf8')
    .then(JSON.parse)
    .then(function (data) {
      test.strictEqual(data.name, 'relike')
    })
})

test('should emit `unhandledRejection` event', function (done) {
  relike(JSON.parse, '{boo:"bar}')
  process.once('unhandledRejection', function (err) {
    test.ifError(!err)
    test.strictEqual(err.name, 'SyntaxError')
    test.ok(/Unexpected token/.test(err.message))
    done()
  })
})

test('should `.promisify` method allow passing `.Promise` to promisified function', function () {
  var relike = create()
  var readFile = relike.promisify(fs.readFile)
  readFile.Promise = require('pinkie') // eslint-disable-line
  var promise = readFile('package.json', 'utf8')

  return promise
    .then(function (res) {
      test.strictEqual(typeof res, 'string')
      test.strictEqual(isBuffer(res), false)
      if (semver.lt(process.version, '0.11.13')) {
        test.strictEqual(promise.___customPromise, true)
        test.strictEqual(promise.Promise.___customPromise, true)
      }
    })
})

test('should use promise passed to `relike.promisify.Promise` and promisifing with `.promisify`', function () {
  var relike = create()
  relike.promisify.Promise = require('pinkie') // eslint-disable-line
  var statFile = relike.promisify(fs.stat)
  var promise = statFile('index.js')

  return promise.then(function (res) {
    if (semver.lt(process.version, '0.11.13')) {
      test.ok(promise.___customPromise === true)
    }
    test.strictEqual(typeof res, 'object')
    test.ok(res.mtime)
  })
})

test('should not use custom promise constructor passed to `relike.Promise` when use `.promisify`', function () {
  var relike = create()
  relike.Promise = require('pinkie') // eslint-disable-line
  var readSync = relike.promisify(fs.readFileSync)
  var promise = readSync('README.md', 'utf8')

  return promise.then(function resolve (result) {
    test.ok(typeof result === 'string')
    if (semver.lt(process.version, '0.11.13')) {
      test.strictEqual(promise.___customPromise, true)
    }
  })
})

test('should promisify with promise module (pinkie) given in `relike.Promise`', function () {
  var relike = create()
  relike.Promise = require('pinkie') // eslint-disable-line
  var promise = relike(fs.readFile, 'package.json')

  return promise.then(function (res) {
    test.strictEqual(isBuffer(res), true)
    if (semver.lt(process.version, '0.11.13')) {
      test.strictEqual(promise.___customPromise, true)
      test.strictEqual(promise.Promise.___customPromise, true)
    }
  })
})
<|endoftext|>


<commit_before>import React, { Component } from "react";
import PropTypes from "prop-types";
import styled from "styled-components";
import FontAwesome from "react-fontawesome";

const BUTTERCUP_LOGO_SMALL = require("../../../resources/buttercup-128.png");
const EXPAND_SPACE_AFTER = 4;
const NOOP = () => {};
const ROW_SIZE_UNIT = 26;

function LazyType(f) {
    return function __lazyType() {
        return f().apply(this, arguments);
    };
}

const LazyDirectoryShape = LazyType(() => DirectoryShape);
const FileShape = PropTypes.shape({
    path: PropTypes.string.isRequired,
    name: PropTypes.string.isRequired
});
const DirectoryShape = PropTypes.shape({
    path: PropTypes.string.isRequired,
    name: PropTypes.string.isRequired,
    directories: PropTypes.arrayOf(LazyDirectoryShape).isRequired,
    files: PropTypes.arrayOf(FileShape).isRequired
});

const Container = styled.div`
    width: 100%;
    display: flex;
    flex-direction: column;
    align-content: stretch;
    margin-bottom: 20px;
    overflow-y: scroll;
`;
const ItemRow = styled.div`
    margin-left: ${props => (props.depth ? props.depth * ROW_SIZE_UNIT : 0)}px;
    height: ${ROW_SIZE_UNIT}px;
    display: flex;
    flex-direction: row;
    justify-content: flex-start;
    align-items: stretch;
    background-color: ${props => (props.selected ? "rgba(0, 183, 172, 0.2)" : "inherit")};
`;
const ExpandBox = styled.div`
    width: ${ROW_SIZE_UNIT}px;
    display: flex;
    justify-content: center;
    align-items: center;
    background-color: ${props => (props.isFile ? "#ddd" : "rgba(0, 183, 172, 1)")};
    color: #fff;
    margin-right: ${EXPAND_SPACE_AFTER}px;
    cursor: ${props => (props.isFile ? "default" : "pointer")};
`;
const ExpandBoxBCUP = styled(ExpandBox)`
    background-image: url(${BUTTERCUP_LOGO_SMALL});
    background-size: 26px;
    background-position: 50% 50%;
`;
const ItemIcon = styled.div`
    width: ${ROW_SIZE_UNIT}px;
    display: flex;
    justify-content: center;
    align-items: center;
    color: ${props => (props.isFile ? "#b2b2b2" : "#f2ac09")};
    font-size: 18px;
    margin-right: 4px;
`;
const ItemText = styled.div`
    display: flex;
    justify-content: flex-start;
    align-items: center;
    font-size: 16px;
    font-weight: bold;
    font-style: ${props => (props.selected ? "italic" : "normal")};
    color: rgb(72, 72, 72);
    cursor: pointer;
`;
const LoaderIconContainer = styled.div`
    width: ${ROW_SIZE_UNIT}px;
    height: ${ROW_SIZE_UNIT}px;
    display: flex;
    justify-content: center;
    align-items: center;
    color: #888;
    margin-left: ${EXPAND_SPACE_AFTER}px;
`;

class RemoteFileTree extends Component {
    static propTypes = {
        directoriesLoading: PropTypes.arrayOf(PropTypes.string).isRequired,
        onCreateRemotePath: PropTypes.func.isRequired,
        onOpenDirectory: PropTypes.func.isRequired,
        onSelectRemotePath: PropTypes.func.isRequired,
        rootDirectory: DirectoryShape,
        selectedFilename: PropTypes.string,
        selectedFilenameNeedsCreation: PropTypes.bool.isRequired
    };

    static defaultProps = {
        onCreateRemotePath: NOOP,
        onOpenDirectory: NOOP,
        onSelectRemotePath: NOOP,
        selectedFilenameNeedsCreation: false
    };

    constructor(props) {
        super(props);
        this.state = {
            openDirectories: ["/"]
        };
    }

    handleExpansionClick(item) {
        const { path } = item;
        if (this.state.openDirectories.includes(path)) {
            // close
            this.setState({
                openDirectories: this.state.openDirectories.filter(dir => dir !== path)
            });
        } else {
            // open
            this.setState({
                openDirectories: [...this.state.openDirectories, path]
            });
            this.props.onOpenDirectory(path);
        }
    }

    handleFileClick(fileItem) {
        this.props.onSelectRemotePath(fileItem.path);
    }

    render() {
        return (
            <Container>
                <Choose>
                    <When condition={!!this.props.rootDirectory}>
                        {this.renderDirectory(this.props.rootDirectory)}
                        {this.renderFiles(this.props.rootDirectory, 1)}
                    </When>
                    <Otherwise>
                        <If condition={this.props.directoriesLoading.includes("/")}>{this.renderLoader("/", 1)}</If>
                    </Otherwise>
                </Choose>
            </Container>
        );
    }

    renderDirectory(dir, depth = 0) {
        const isOpen = this.state.openDirectories.includes(dir.path);
        const isLoading = this.props.directoriesLoading.includes(dir.path);
        const name = dir.name.trim().length > 0 ? dir.name : "/";
        const thisItem = (
            <ItemRow depth={depth} key={dir.path}>
                <ExpandBox onClick={() => this.handleExpansionClick(dir)}>
                    <Choose>
                        <When condition={isOpen}>
                            <FontAwesome name="minus" />
                        </When>
                        <Otherwise>
                            <FontAwesome name="plus" />
                        </Otherwise>
                    </Choose>
                </ExpandBox>
                <ItemIcon isFile={false}>
                    <FontAwesome name="folder" />
                </ItemIcon>
                <ItemText onClick={() => this.handleExpansionClick(dir)}>{name}</ItemText>
            </ItemRow>
        );
        const allItems = [null];
        if (isOpen) {
            // Directory is open, so add children
            allItems.push(...dir.directories);
        }
        return [
            <For each="directory" of={allItems}>
                <Choose>
                    <When condition={directory === null}>{thisItem}</When>
                    <Otherwise>{this.renderDirectory(directory, depth + 1)}</Otherwise>
                </Choose>
            </For>,
            isOpen ? this.renderFiles(dir, depth + 1) : null,
            isOpen && isLoading ? this.renderLoader(dir.path, depth + 1) : null
        ];
    }

    renderFiles(dir, depth = 0) {
        return (
            <For each="file" of={dir.files}>
                <ItemRow depth={depth} key={file.path} selected={file.path === this.props.selectedFilename}>
                    <Choose>
                        <When condition={/\.bcup$/i.test(file.name)}>
                            <ExpandBoxBCUP isFile={true} />
                        </When>
                        <Otherwise>
                            <ExpandBox isFile={true} />
                        </Otherwise>
                    </Choose>
                    <ItemIcon isFile={true}>
                        <FontAwesome name="file" />
                    </ItemIcon>
                    <ItemText
                        onClick={() => this.handleFileClick(file)}
                        selected={file.path === this.props.selectedFilename}
                    >
                        {file.name}
                    </ItemText>
                </ItemRow>
            </For>
        );
    }

    renderLoader(parentPath, depth = 0) {
        return (
            <ItemRow depth={depth} key={`loader:${parentPath}`}>
                <LoaderIconContainer>
                    <FontAwesome name="repeat" spin />
                </LoaderIconContainer>
            </ItemRow>
        );
    }
}

export default RemoteFileTree;
<commit_msg>Fix duplicate files in root listing<commit_after>import React, { Component } from "react";
import PropTypes from "prop-types";
import styled from "styled-components";
import FontAwesome from "react-fontawesome";

const BUTTERCUP_LOGO_SMALL = require("../../../resources/buttercup-128.png");
const EXPAND_SPACE_AFTER = 4;
const NOOP = () => {};
const ROW_SIZE_UNIT = 26;

function LazyType(f) {
    return function __lazyType() {
        return f().apply(this, arguments);
    };
}

const LazyDirectoryShape = LazyType(() => DirectoryShape);
const FileShape = PropTypes.shape({
    path: PropTypes.string.isRequired,
    name: PropTypes.string.isRequired
});
const DirectoryShape = PropTypes.shape({
    path: PropTypes.string.isRequired,
    name: PropTypes.string.isRequired,
    directories: PropTypes.arrayOf(LazyDirectoryShape).isRequired,
    files: PropTypes.arrayOf(FileShape).isRequired
});

const Container = styled.div`
    width: 100%;
    display: flex;
    flex-direction: column;
    align-content: stretch;
    margin-bottom: 20px;
    overflow-y: scroll;
`;
const ItemRow = styled.div`
    margin-left: ${props => (props.depth ? props.depth * ROW_SIZE_UNIT : 0)}px;
    height: ${ROW_SIZE_UNIT}px;
    display: flex;
    flex-direction: row;
    justify-content: flex-start;
    align-items: stretch;
    background-color: ${props => (props.selected ? "rgba(0, 183, 172, 0.2)" : "inherit")};
`;
const ExpandBox = styled.div`
    width: ${ROW_SIZE_UNIT}px;
    display: flex;
    justify-content: center;
    align-items: center;
    background-color: ${props => (props.isFile ? "#ddd" : "rgba(0, 183, 172, 1)")};
    color: #fff;
    margin-right: ${EXPAND_SPACE_AFTER}px;
    cursor: ${props => (props.isFile ? "default" : "pointer")};
`;
const ExpandBoxBCUP = styled(ExpandBox)`
    background-image: url(${BUTTERCUP_LOGO_SMALL});
    background-size: 26px;
    background-position: 50% 50%;
`;
const ItemIcon = styled.div`
    width: ${ROW_SIZE_UNIT}px;
    display: flex;
    justify-content: center;
    align-items: center;
    color: ${props => (props.isFile ? "#b2b2b2" : "#f2ac09")};
    font-size: 18px;
    margin-right: 4px;
`;
const ItemText = styled.div`
    display: flex;
    justify-content: flex-start;
    align-items: center;
    font-size: 16px;
    font-weight: bold;
    font-style: ${props => (props.selected ? "italic" : "normal")};
    color: rgb(72, 72, 72);
    cursor: pointer;
`;
const LoaderIconContainer = styled.div`
    width: ${ROW_SIZE_UNIT}px;
    height: ${ROW_SIZE_UNIT}px;
    display: flex;
    justify-content: center;
    align-items: center;
    color: #888;
    margin-left: ${EXPAND_SPACE_AFTER}px;
`;

class RemoteFileTree extends Component {
    static propTypes = {
        directoriesLoading: PropTypes.arrayOf(PropTypes.string).isRequired,
        onCreateRemotePath: PropTypes.func.isRequired,
        onOpenDirectory: PropTypes.func.isRequired,
        onSelectRemotePath: PropTypes.func.isRequired,
        rootDirectory: DirectoryShape,
        selectedFilename: PropTypes.string,
        selectedFilenameNeedsCreation: PropTypes.bool.isRequired
    };

    static defaultProps = {
        onCreateRemotePath: NOOP,
        onOpenDirectory: NOOP,
        onSelectRemotePath: NOOP,
        selectedFilenameNeedsCreation: false
    };

    constructor(props) {
        super(props);
        this.state = {
            openDirectories: ["/"]
        };
    }

    handleExpansionClick(item) {
        const { path } = item;
        if (this.state.openDirectories.includes(path)) {
            // close
            this.setState({
                openDirectories: this.state.openDirectories.filter(dir => dir !== path)
            });
        } else {
            // open
            this.setState({
                openDirectories: [...this.state.openDirectories, path]
            });
            this.props.onOpenDirectory(path);
        }
    }

    handleFileClick(fileItem) {
        this.props.onSelectRemotePath(fileItem.path);
    }

    render() {
        return (
            <Container>
                <Choose>
                    <When condition={!!this.props.rootDirectory}>
                        {this.renderDirectory(this.props.rootDirectory)}
                        {/*this.renderFiles(this.props.rootDirectory, 1)*/}
                    </When>
                    <Otherwise>
                        <If condition={this.props.directoriesLoading.includes("/")}>{this.renderLoader("/", 1)}</If>
                    </Otherwise>
                </Choose>
            </Container>
        );
    }

    renderDirectory(dir, depth = 0) {
        const isOpen = this.state.openDirectories.includes(dir.path);
        const isLoading = this.props.directoriesLoading.includes(dir.path);
        const name = dir.name.trim().length > 0 ? dir.name : "/";
        const thisItem = (
            <ItemRow depth={depth} key={dir.path}>
                <ExpandBox onClick={() => this.handleExpansionClick(dir)}>
                    <Choose>
                        <When condition={isOpen}>
                            <FontAwesome name="minus" />
                        </When>
                        <Otherwise>
                            <FontAwesome name="plus" />
                        </Otherwise>
                    </Choose>
                </ExpandBox>
                <ItemIcon isFile={false}>
                    <FontAwesome name="folder" />
                </ItemIcon>
                <ItemText onClick={() => this.handleExpansionClick(dir)}>{name}</ItemText>
            </ItemRow>
        );
        const allItems = [null];
        if (isOpen) {
            // Directory is open, so add children
            allItems.push(...dir.directories);
        }
        return [
            <For each="directory" of={allItems}>
                <Choose>
                    <When condition={directory === null}>{thisItem}</When>
                    <Otherwise>{this.renderDirectory(directory, depth + 1)}</Otherwise>
                </Choose>
            </For>,
            isOpen ? this.renderFiles(dir, depth + 1) : null,
            isOpen && isLoading ? this.renderLoader(dir.path, depth + 1) : null
        ];
    }

    renderFiles(dir, depth = 0) {
        return (
            <For each="file" of={dir.files}>
                <ItemRow depth={depth} key={file.path} selected={file.path === this.props.selectedFilename}>
                    <Choose>
                        <When condition={/\.bcup$/i.test(file.name)}>
                            <ExpandBoxBCUP isFile={true} />
                        </When>
                        <Otherwise>
                            <ExpandBox isFile={true} />
                        </Otherwise>
                    </Choose>
                    <ItemIcon isFile={true}>
                        <FontAwesome name="file" />
                    </ItemIcon>
                    <ItemText
                        onClick={() => this.handleFileClick(file)}
                        selected={file.path === this.props.selectedFilename}
                    >
                        {file.name}
                    </ItemText>
                </ItemRow>
            </For>
        );
    }

    renderLoader(parentPath, depth = 0) {
        return (
            <ItemRow depth={depth} key={`loader:${parentPath}`}>
                <LoaderIconContainer>
                    <FontAwesome name="repeat" spin />
                </LoaderIconContainer>
            </ItemRow>
        );
    }
}

export default RemoteFileTree;
<|endoftext|>