<commit_before>import { registerOption } from 'pretty-text/pretty-text';

registerOption((siteSettings, opts) => {
  opts.features.furigana = !!siteSettings.furigana_enabled;
  opts.furiganaForms = siteSettings.furigana_plugin_forms;
  opts.furiganaFallbackBrackets = siteSettings.furigana_fallback_brackets;
  opts.furiganaStrictMode = !!siteSettings.furiganaStrictMode;
  opts.furiganaAutoBracketSets = siteSettings.furigana_plugin_auto_bracket_sets;
});

// This function escapes special characters for use in a regex constructor.
function escapeForRegex(string) {
  return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
}

const kanjiRange = '\\u4e00-\\u9faf';
const kanaWithAnnotations = '\\u3041-\\u3095\\u3099-\\u309c\\u3081-\\u30fa\\u30fc';
const furiganaSeperators = '.．。・';
const seperatorRegex = new RegExp(`[${furiganaSeperators}]`, 'g');

let regexList = [];
let previousFuriganaForms = '';

function updateRegexList(furiganaForms) {
  previousFuriganaForms = furiganaForms;
  const innerRegexString = '(?:[^\\u0000-\\u007F]|\\w)+';
  let formArray = furiganaForms.split('|');
  if (formArray.length === 0) {
    formArray = ['[]:^:()'];
  }
  regexList = formArray.map(form => {
    let furiganaComponents = form.split(':');
    if (furiganaComponents.length !== 3) {
      furiganaComponents = ['[]', '^', '()'];
    }
    const mainBrackets = furiganaComponents[0];
    const seperator = furiganaComponents[1];
    const furiganaBrackets = furiganaComponents[2];
    return new RegExp(
      escapeForRegex(mainBrackets[0]) +
      '(' + innerRegexString + ')' +
      escapeForRegex(mainBrackets[1]) +
      escapeForRegex(seperator) +
      escapeForRegex(furiganaBrackets[0]) +
      '(' + innerRegexString + ')' +
      escapeForRegex(furiganaBrackets[1]),
      'g'
    );
  });
}

let autoRegexList = [];
let previousAutoBracketSets = '';

function updateAutoRegexList(autoBracketSets) {
  previousAutoBracketSets = autoBracketSets;
  autoRegexList = autoBracketSets.split('|').map(brackets => {
    /*
      Sample built regex (hiragana only):
      (^|[^\u4e00-\u9faf])([\u4e00-\u9faf]+)([\u3041-\u3095\u3099-\u309c]*)【([^\u4e00-\u9faf]+)】
    */
    return new RegExp(
      `(^|[^${escapeForRegex(brackets)}${kanjiRange}])` +
      `([${kanjiRange}]+)` +
      `([${kanaWithAnnotations}]*)` +
      escapeForRegex(brackets[0]) +
      `((?:[^${escapeForRegex(brackets)}${kanjiRange}]|\w)+)` +
      escapeForRegex(brackets[1]),
      'g'
    );
  });
}

let replacementTemplate = '';
let replacementBrackets = '';

function updateReplacementTemplate(furiganaFallbackBrackets) {
  if (furiganaFallbackBrackets.length !== 2) {
    furiganaFallbackBrackets = '【】';
  }
  replacementBrackets = furiganaFallbackBrackets;
  replacementTemplate = `<ruby>$1<rp>${furiganaFallbackBrackets[0]}</rp><rt>$2</rt><rp>${furiganaFallbackBrackets[1]}</rp></ruby>`;
}

updateReplacementTemplate('【】');

function addFurigana(text, options) {
  if (options.furiganaForms !== previousFuriganaForms) {
    updateRegexList(options.furiganaForms);
  }
  if (options.furiganaFallbackBrackets !== replacementBrackets) {
    updateReplacementTemplate(options.furiganaFallbackBrackets);
  }
  regexList.forEach(regex => {
    text = text.replace(regex, (match, match1, match2, offset, mainText) => {
      if (match.indexOf('\\') === -1 && mainText[offset - 1] !== '\\') {
        return replacementTemplate.replace('$1', match1).replace('$2', match2);
      } else {
        return match;
      }
    });
  });

  if (!options.furiganaStrictMode) {
    if (options.furiganaAutoBracketSets !== previousAutoBracketSets) {
      updateAutoRegexList(options.furiganaAutoBracketSets);
    }
    autoRegexList.forEach(regex => {
      text = text.replace(regex, (match, preWordTerminator, wordKanji, wordKanaSuffix, furiganaText, offset, mainText) => {
        if (match.indexOf('\\') === -1) {
          let rubies = [];

          let furigana = furiganaText;
          let stem = (' ' + wordKanaSuffix).slice(1);
          for (let i = furiganaText.length - 1; i >= 0; i--) {
            if (wordKanaSuffix.length === 0) {
              furigana = furiganaText.substring(0, i + 1);
              break;
            }
            if (furiganaText[i] !== wordKanaSuffix.slice(-1)) {
              furigana = furiganaText.substring(0, i + 1);
              break;
            }
            wordKanaSuffix = wordKanaSuffix.slice(0, -1);
          }

          if (furiganaSeperators.split('').reduce(
            (noSeperator, seperator) => {
              return noSeperator && (furigana.indexOf(seperator) === -1);
            },
            true
          )) {
            rubies = [replacementTemplate.replace('$1', wordKanji).replace('$2', furigana)];
          } else {
            let kanaParts = furigana.split(seperatorRegex);
            let kanji = wordKanji.split('');
            if (kanaParts.length !== kanji.length) {
              rubies = [replacementTemplate.replace('$1', wordKanji).replace('$2', furigana)];
            } else {
              for (let i = 0; i < wordKanji.length; i++) {
                rubies.push(replacementTemplate.replace('$1', kanji[i]).replace('$2', kanaParts[i]));
              }
            }
          }

          return preWordTerminator + rubies.join('') + stem;
        } else {
          return match;
        }
      });
    });
  }
  return text;
}

function handleEscapedSpecialBrackets(text) {
  // By default 【 and 】 cannot be escaped in markdown, this will remove backslashes from in front of them to give that effect.
  return text.replace(/\\([【】])/g, '$1');
}

export function setup(helper) {
  helper.whiteList([
    'ruby',
    'rt',
    'rp'
  ]);

  helper.addPreProcessor(text => {
    return handleEscapedSpecialBrackets(addFurigana(text, helper.getOptions()));
  });
}
<commit_msg>Add extended pattern matching to standard furigana forms<commit_after>import { registerOption } from 'pretty-text/pretty-text';

registerOption((siteSettings, opts) => {
  opts.features.furigana = !!siteSettings.furigana_enabled;
  opts.furiganaForms = siteSettings.furigana_plugin_forms;
  opts.furiganaFallbackBrackets = siteSettings.furigana_fallback_brackets;
  opts.furiganaStrictMode = !!siteSettings.furiganaStrictMode;
  opts.furiganaAutoBracketSets = siteSettings.furigana_plugin_auto_bracket_sets;
});

// This function escapes special characters for use in a regex constructor.
function escapeForRegex(string) {
  return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
}

function emptyStringFilter(block) {
  return block !== '';
}

const kanjiRange = '\\u4e00-\\u9faf';
const kanjiBlockRegex = new RegExp(`[${kanjiRange}]+`, 'g');
const nonKanjiBlockRegex = new RegExp(`[^${kanjiRange}]+`, 'g');
const kanaWithAnnotations = '\\u3041-\\u3095\\u3099-\\u309c\\u3081-\\u30fa\\u30fc';
const furiganaSeperators = '.．。・';
const seperatorRegex = new RegExp(`[${furiganaSeperators}]`, 'g');

const singleKanjiRegex = new RegExp(`^[${kanjiRange}]$`);
function isKanji(character) {
  return character.match(singleKanjiRegex);
}

let regexList = [];
let previousFuriganaForms = '';

function updateRegexList(furiganaForms) {
  previousFuriganaForms = furiganaForms;
  const innerRegexString = '(?:[^\\u0000-\\u007F]|\\w)+';
  let formArray = furiganaForms.split('|');
  if (formArray.length === 0) {
    formArray = ['[]:^:()'];
  }
  regexList = formArray.map(form => {
    let furiganaComponents = form.split(':');
    if (furiganaComponents.length !== 3) {
      furiganaComponents = ['[]', '^', '()'];
    }
    const mainBrackets = furiganaComponents[0];
    const seperator = furiganaComponents[1];
    const furiganaBrackets = furiganaComponents[2];
    return new RegExp(
      escapeForRegex(mainBrackets[0]) +
      '(' + innerRegexString + ')' +
      escapeForRegex(mainBrackets[1]) +
      escapeForRegex(seperator) +
      escapeForRegex(furiganaBrackets[0]) +
      '(' + innerRegexString + ')' +
      escapeForRegex(furiganaBrackets[1]),
      'g'
    );
  });
}

let autoRegexList = [];
let previousAutoBracketSets = '';

function updateAutoRegexList(autoBracketSets) {
  previousAutoBracketSets = autoBracketSets;
  autoRegexList = autoBracketSets.split('|').map(brackets => {
    /*
      Sample built regex (hiragana only):
      (^|[^\u4e00-\u9faf])([\u4e00-\u9faf]+)([\u3041-\u3095\u3099-\u309c]*)【([^\u4e00-\u9faf]+)】
    */
    return new RegExp(
      `(^|[^${escapeForRegex(brackets)}${kanjiRange}])` +
      `([${kanjiRange}]+)` +
      `([${kanaWithAnnotations}]*)` +
      escapeForRegex(brackets[0]) +
      `((?:[^${escapeForRegex(brackets)}${kanjiRange}]|\w)+)` +
      escapeForRegex(brackets[1]),
      'g'
    );
  });
}

let replacementTemplate = '';
let replacementBrackets = '';

function updateReplacementTemplate(furiganaFallbackBrackets) {
  if (furiganaFallbackBrackets.length !== 2) {
    furiganaFallbackBrackets = '【】';
  }
  replacementBrackets = furiganaFallbackBrackets;
  replacementTemplate = `<ruby>$1<rp>${furiganaFallbackBrackets[0]}</rp><rt>$2</rt><rp>${furiganaFallbackBrackets[1]}</rp></ruby>`;
}

updateReplacementTemplate('【】');

function addFurigana(text, options) {
  if (options.furiganaForms !== previousFuriganaForms) {
    updateRegexList(options.furiganaForms);
  }
  if (options.furiganaFallbackBrackets !== replacementBrackets) {
    updateReplacementTemplate(options.furiganaFallbackBrackets);
  }
  regexList.forEach(regex => {
    // 繰り返す
    // くりかえす
    /*
      りす
      繰返

      り
        く - かえす
        繰り
      す
        かえ
        繰り返す

    */
    text = text.replace(regex, (match, wordText, furiganaText, offset, mainText) => {
      if (match.indexOf('\\') === -1 && mainText[offset - 1] !== '\\') {
        let nonKanji = wordText.split(kanjiBlockRegex).filter(emptyStringFilter);
        if (nonKanji.length === 0) {
          return replacementTemplate.replace('$1', wordText).replace('$2', furiganaText);
        } else {
          let kanji = wordText.split(nonKanjiBlockRegex).filter(emptyStringFilter);
          let replacementText = '';
          nonKanji.forEach((currentNonKanji, index) => {
            if (furiganaText === undefined) {
              if (index < kanji.length) {
                replacementText += kanji[index];
              }

              replacementText += currentNonKanji;
              return;
            }
            let splitFurigana = furiganaText.split(new RegExp(escapeForRegex(currentNonKanji) + '(.*)')).filter(emptyStringFilter);
            replacementText += replacementTemplate.replace('$1', kanji[index]).replace('$2', splitFurigana[0]);
            replacementText += currentNonKanji;
            furiganaText = splitFurigana[1];
          });
          return replacementText;
        }
      } else {
        return match;
      }
    });
  });

  if (!options.furiganaStrictMode) {
    if (options.furiganaAutoBracketSets !== previousAutoBracketSets) {
      updateAutoRegexList(options.furiganaAutoBracketSets);
    }
    autoRegexList.forEach(regex => {
      text = text.replace(regex, (match, preWordTerminator, wordKanji, wordKanaSuffix, furiganaText, offset, mainText) => {
        if (match.indexOf('\\') === -1) {
          let rubies = [];

          let furigana = furiganaText;
          let stem = (' ' + wordKanaSuffix).slice(1);
          for (let i = furiganaText.length - 1; i >= 0; i--) {
            if (wordKanaSuffix.length === 0) {
              furigana = furiganaText.substring(0, i + 1);
              break;
            }
            if (furiganaText[i] !== wordKanaSuffix.slice(-1)) {
              furigana = furiganaText.substring(0, i + 1);
              break;
            }
            wordKanaSuffix = wordKanaSuffix.slice(0, -1);
          }

          if (furiganaSeperators.split('').reduce(
            (noSeperator, seperator) => {
              return noSeperator && (furigana.indexOf(seperator) === -1);
            },
            true
          )) {
            rubies = [replacementTemplate.replace('$1', wordKanji).replace('$2', furigana)];
          } else {
            let kanaParts = furigana.split(seperatorRegex);
            let kanji = wordKanji.split('');
            if (kanaParts.length !== kanji.length) {
              rubies = [replacementTemplate.replace('$1', wordKanji).replace('$2', furigana)];
            } else {
              for (let i = 0; i < wordKanji.length; i++) {
                rubies.push(replacementTemplate.replace('$1', kanji[i]).replace('$2', kanaParts[i]));
              }
            }
          }

          return preWordTerminator + rubies.join('') + stem;
        } else {
          return match;
        }
      });
    });
  }
  return text;
}

function handleEscapedSpecialBrackets(text) {
  // By default 【 and 】 cannot be escaped in markdown, this will remove backslashes from in front of them to give that effect.
  return text.replace(/\\([【】])/g, '$1');
}

export function setup(helper) {
  helper.whiteList([
    'ruby',
    'rt',
    'rp'
  ]);

  helper.addPreProcessor(text => {
    return handleEscapedSpecialBrackets(addFurigana(text, helper.getOptions()));
  });
}
<|endoftext|>


<commit_before>// See the shakacode/shakapacker README and docs directory for advice on customizing your webpackConfig.

const { webpackConfig, merge } = require('shakapacker')
const webpack = require('webpack');

// Custom ERB loader to disable Spring and prevent crashes
const erb = require("./loaders/erb");

// This setting will change the absolute path used to refer
// external files (images, fonts, ...) in the generated assets
const relative_url_root = process.env.RAILS_RELATIVE_URL_ROOT || '';
const public_output_path = webpackConfig.output.publicPath;

const envConfig = module.exports = {
    output: {
        publicPath: relative_url_root + public_output_path
    },
    module: {
        rules: [
            erb
        ]
    },
    resolve: {
        extensions: ['.css', '.ts', '.tsx'],
        alias: {
            $: 'jquery/src/jquery',
            jquery: 'jquery/src/jquery',
            vis$: 'vis-timeline/standalone',
        }
    },
    plugins: [
        new webpack.ProvidePlugin({
            $: 'jquery',
            JQuery: 'jquery',
            jQuery: 'jquery',
            jquery: 'jquery',
            'window.Tether': "tether",
            Popper: ['popper.js', 'default'],
            _: 'underscore',
            vis: 'vis',
            d3: 'd3',
            Sentry: '@sentry/browser',
            Sortable: 'sortablejs',
        })
    ],
    performance: {
        // Turn off size warnings for large assets
        hints: false
    },
    stats: 'minimal'
}

module.exports = merge(webpackConfig, envConfig)
<commit_msg>Add options to minify Webpack output and rearrange webpack.config.js<commit_after>// See the shakacode/shakapacker README and docs directory for advice on customizing your webpackConfig.

const { webpackConfig, merge } = require('shakapacker')
const webpack = require('webpack');

const CompressionPlugin = require("compression-webpack-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const TerserPlugin = require("terser-webpack-plugin");

// Custom ERB loader to disable Spring and prevent crashes
const erb = require("./loaders/erb");

// This setting will change the absolute path used to refer
// external files (images, fonts, ...) in the generated assets
const relative_url_root = process.env.RAILS_RELATIVE_URL_ROOT || '';
const public_output_path = webpackConfig.output.publicPath;

const envConfig = module.exports = {
    module: {
        rules: [
            erb
        ]
    },
    optimization: {
        minimize: true,
        minimizer: [
            new TerserPlugin(),
            new CssMinimizerPlugin()
        ],
    },
    output: {
        publicPath: relative_url_root + public_output_path
    },
    performance: {
        // Turn off size warnings for large assets
        hints: false
    },
    plugins: [
        new webpack.ProvidePlugin({
            $: 'jquery',
            JQuery: 'jquery',
            jQuery: 'jquery',
            jquery: 'jquery',
            'window.Tether': "tether",
            Popper: ['popper.js', 'default'],
            _: 'underscore',
            vis: 'vis',
            d3: 'd3',
            Sentry: '@sentry/browser',
            Sortable: 'sortablejs',
        }),
        new CompressionPlugin(),
        new MiniCssExtractPlugin(),
    ],
    resolve: {
        extensions: ['.css', '.ts', '.tsx'],
        alias: {
            $: 'jquery/src/jquery',
            jquery: 'jquery/src/jquery',
            vis$: 'vis-timeline/standalone',
        }
    },
    stats: 'minimal',
}

module.exports = merge(webpackConfig, envConfig)
<|endoftext|>


<commit_before>/**
 * Notification component.
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://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.
 */

/**
 * External dependencies
 */
import PropTypes from 'prop-types';
import classnames from 'classnames';
import map from 'lodash/map';
import { useMount } from 'react-use';

/*
 * WordPress dependencies
 */
import { useState, useRef, Fragment, isValidElement } from '@wordpress/element';

/*
 * Internal dependencies
 */
import GoogleLogoIcon from '../../../svg/logo-g.svg';
import { sanitizeHTML } from '../../util/sanitize';
import DataBlock from '../DataBlock';
import Button from '../Button';
import Warning from './warning';
import Error from './error';
import Link from '../Link';
import ModuleIcon from '../ModuleIcon';
import { getItem, setItem, deleteItem } from '../../googlesitekit/api/cache';

function Notification( {
	dismissExpires,
	showOnce,
	onDismiss,
	onCTAClick,
	children,
	id,
	className,
	title,
	description,
	blockData,
	WinImageSVG,
	SmallImageSVG,
	format,
	learnMoreURL,
	learnMoreDescription,
	learnMoreLabel,
	ctaLink,
	ctaLabel,
	ctaTarget,
	type,
	dismiss,
	isDismissable,
	logo,
	module,
	moduleName,
	pageIndex,
	anchorLink,
	anchorLinkLabel,
} ) {
	// Closed notifications are invisible, but still occupy space.
	const [ isClosed, setIsClosed ] = useState( false );
	// Start with an undefined dismissed state due to async resolution.
	const [ isDismissed, setIsDismissed ] = useState( undefined );
	const cardRef = useRef();
	const cacheKeyDismissed = `notification::dismissed::${ id }`;
	// Persists the notification dismissal to browser storage.
	// Dismissed notifications don't expire.
	const persistDismissal = () => setItem( cacheKeyDismissed, new Date(), { ttl: null } );

	useMount( async () => {
		if ( dismissExpires > 0 ) {
			await expireDismiss();
		}

		const { cacheHit } = await getItem( cacheKeyDismissed );
		setIsDismissed( cacheHit );

		if ( showOnce ) {
			// Set the dismissed flag in cache without immediately hiding it.
			await persistDismissal();
		}
	} );

	async function handleDismiss( e ) {
		e.persist();
		e.preventDefault();

		if ( onDismiss ) {
			await onDismiss( e );
		}
		dismissNotification();
	}

	function dismissNotification() {
		const card = cardRef.current;

		setIsClosed( true );

		setTimeout( async () => {
			await persistDismissal();

			if ( card?.style ) {
				card.style.display = 'none';
			}

			// Emit an event for the notification counter to listen for.
			const event = new Event( 'notificationDismissed' );
			document.dispatchEvent( event );
		}, 350 );
	}

	async function handleCTAClick( e ) {
		e.persist();

		if ( onCTAClick ) {
			await onCTAClick( e );
		}

		if ( isDismissable ) {
			dismissNotification();
		}
	}

	async function expireDismiss() {
		const { value: dismissed } = await getItem( cacheKeyDismissed );

		if ( dismissed ) {
			const expiration = new Date( dismissed );
			expiration.setSeconds( expiration.getSeconds() + parseInt( dismissExpires, 10 ) );

			if ( expiration < new Date() ) {
				await deleteItem( cacheKeyDismissed );
			}
		}
	}

	// isDismissed will be undefined until resolved from browser storage.
	if ( undefined === isDismissed || isDismissed ) {
		return null;
	}

	const closedClass = isClosed ? 'is-closed' : 'is-open';
	const inlineLayout = 'large' === format && 'win-stats-increase' === type;

	let layout = 'mdc-layout-grid__cell--span-12';
	if ( 'large' === format ) {
		layout = 'mdc-layout-grid__cell--order-2-phone ' +
				'mdc-layout-grid__cell--order-1-tablet ' +
				'mdc-layout-grid__cell--span-6-tablet ' +
				'mdc-layout-grid__cell--span-8-desktop ';

		if ( inlineLayout ) {
			layout = 'mdc-layout-grid__cell--order-2-phone ' +
						'mdc-layout-grid__cell--order-1-tablet ' +
						'mdc-layout-grid__cell--span-5-tablet ' +
						'mdc-layout-grid__cell--span-8-desktop ';
		}
	} else if ( 'small' === format ) {
		layout = 'mdc-layout-grid__cell--span-11-desktop ' +
				'mdc-layout-grid__cell--span-7-tablet ' +
				'mdc-layout-grid__cell--span-3-phone';
	}

	let icon;
	if ( 'win-warning' === type ) {
		icon = <Warning />;
	} else if ( 'win-error' === type ) {
		icon = <Error />;
	} else {
		icon = '';
	}

	const dataBlockMarkup = (
		<Fragment>
			{ blockData &&

				{
					map( blockData, ( block, i ) => {
						return (

									<DataBlock { ...block } />

						);
					} )
				}

			}
		</Fragment>
	);

	const inlineMarkup = (
		<Fragment>
			{ title &&

				{ title }

			}
			{ anchorLink && anchorLinkLabel &&

				<Link href={ anchorLink }>
					{ anchorLinkLabel }
				</Link>

			}
			{ description &&

					{ isValidElement( description ) ? description : (

					) }

					{ learnMoreLabel &&
					<Fragment>
						{ ' ' }
						<Link href={ learnMoreURL } external inherit>
							{ learnMoreLabel }
						</Link>
						{ learnMoreDescription }
					</Fragment>
					}
					{ pageIndex &&
					{ pageIndex }
					}

			}
			{ children }
		</Fragment>
	);

	const logoSVG = module
		? <ModuleIcon slug={ module } size={ 19 } />
		: <GoogleLogoIcon height="34" width="32" />;

	return (
		<section
			id={ id }
			ref={ cardRef }
			className={ classnames(
				className,
				'googlesitekit-publisher-win',
				{
					[ `googlesitekit-publisher-win--${ format }` ]: format,
					[ `googlesitekit-publisher-win--${ type }` ]: type,
					[ `googlesitekit-publisher-win--${ closedClass }` ]: closedClass,
				},
			) }
		>

					{ logo &&

							{ logoSVG }

						{ moduleName &&

							{ moduleName }

						}

					}

					{ SmallImageSVG &&

						<SmallImageSVG />

					}

						{ inlineLayout ? (

									{ inlineMarkup }

									{ dataBlockMarkup }

						) : (
							<Fragment>
								{ inlineMarkup }
								{ dataBlockMarkup }
							</Fragment>
						) }

						{ ctaLink &&
						<Button
							className="googlesitekit-notification__cta"
							href={ ctaLink }
							target={ ctaTarget }
							onClick={ handleCTAClick }
						>
							{ ctaLabel }
						</Button>
						}

						{ isDismissable && dismiss &&
						<Link onClick={ handleDismiss }>
							{ dismiss }
						</Link>
						}

					{ WinImageSVG &&

							<WinImageSVG />

					}

					{ ( 'win-error' === type || 'win-warning' === type ) &&

							{ icon }

					}

	);
}

Notification.propTypes = {
	id: PropTypes.string.isRequired,
	className: PropTypes.string,
	title: PropTypes.string.isRequired,
	description: PropTypes.node,
	learnMoreURL: PropTypes.string,
	learnMoreDescription: PropTypes.string,
	learnMoreLabel: PropTypes.string,
	blockData: PropTypes.array,
	WinImageSVG: PropTypes.elementType,
	SmallImageSVG: PropTypes.elementType,
	format: PropTypes.string,
	ctaLink: PropTypes.string,
	ctaLabel: PropTypes.string,
	type: PropTypes.string,
	dismiss: PropTypes.string,
	isDismissable: PropTypes.bool,
	logo: PropTypes.bool,
	module: PropTypes.string,
	moduleName: PropTypes.string,
	pageIndex: PropTypes.string,
	dismissExpires: PropTypes.number,
	showOnce: PropTypes.bool,
	onCTAClick: PropTypes.func,
	onDismiss: PropTypes.func,
	anchorLink: PropTypes.string,
	anchorLinkLabel: PropTypes.string,
};

Notification.defaultProps = {
	isDismissable: true,
	className: '',
	dismissExpires: 0,
	showOnce: false,
};

export default Notification;
<commit_msg>Keep initial undismissed state and only set if dismissable.<commit_after>/**
 * Notification component.
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://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.
 */

/**
 * External dependencies
 */
import PropTypes from 'prop-types';
import classnames from 'classnames';
import map from 'lodash/map';
import { useMount } from 'react-use';

/*
 * WordPress dependencies
 */
import { useState, useRef, Fragment, isValidElement } from '@wordpress/element';

/*
 * Internal dependencies
 */
import GoogleLogoIcon from '../../../svg/logo-g.svg';
import { sanitizeHTML } from '../../util/sanitize';
import DataBlock from '../DataBlock';
import Button from '../Button';
import Warning from './warning';
import Error from './error';
import Link from '../Link';
import ModuleIcon from '../ModuleIcon';
import { getItem, setItem, deleteItem } from '../../googlesitekit/api/cache';

function Notification( {
	dismissExpires,
	showOnce,
	onDismiss,
	onCTAClick,
	children,
	id,
	className,
	title,
	description,
	blockData,
	WinImageSVG,
	SmallImageSVG,
	format,
	learnMoreURL,
	learnMoreDescription,
	learnMoreLabel,
	ctaLink,
	ctaLabel,
	ctaTarget,
	type,
	dismiss,
	isDismissable,
	logo,
	module,
	moduleName,
	pageIndex,
	anchorLink,
	anchorLinkLabel,
} ) {
	// Closed notifications are invisible, but still occupy space.
	const [ isClosed, setIsClosed ] = useState( false );
	// Start with an undefined dismissed state due to async resolution.
	const [ isDismissed, setIsDismissed ] = useState( false );
	const cardRef = useRef();
	const cacheKeyDismissed = `notification::dismissed::${ id }`;
	// Persists the notification dismissal to browser storage.
	// Dismissed notifications don't expire.
	const persistDismissal = () => setItem( cacheKeyDismissed, new Date(), { ttl: null } );

	useMount( async () => {
		if ( dismissExpires > 0 ) {
			await expireDismiss();
		}

		if ( isDismissable ) {
			const { cacheHit } = await getItem( cacheKeyDismissed );
			setIsDismissed( cacheHit );
		}

		if ( showOnce ) {
			// Set the dismissed flag in cache without immediately hiding it.
			await persistDismissal();
		}
	} );

	async function handleDismiss( e ) {
		e.persist();
		e.preventDefault();

		if ( onDismiss ) {
			await onDismiss( e );
		}
		dismissNotification();
	}

	function dismissNotification() {
		const card = cardRef.current;

		setIsClosed( true );

		setTimeout( async () => {
			await persistDismissal();

			if ( card?.style ) {
				card.style.display = 'none';
			}

			// Emit an event for the notification counter to listen for.
			const event = new Event( 'notificationDismissed' );
			document.dispatchEvent( event );
		}, 350 );
	}

	async function handleCTAClick( e ) {
		e.persist();

		if ( onCTAClick ) {
			await onCTAClick( e );
		}

		if ( isDismissable ) {
			dismissNotification();
		}
	}

	async function expireDismiss() {
		const { value: dismissed } = await getItem( cacheKeyDismissed );

		if ( dismissed ) {
			const expiration = new Date( dismissed );
			expiration.setSeconds( expiration.getSeconds() + parseInt( dismissExpires, 10 ) );

			if ( expiration < new Date() ) {
				await deleteItem( cacheKeyDismissed );
			}
		}
	}

	// isDismissed will be undefined until resolved from browser storage.
	if ( isDismissable && ( undefined === isDismissed || isDismissed ) ) {
		return null;
	}

	const closedClass = isClosed ? 'is-closed' : 'is-open';
	const inlineLayout = 'large' === format && 'win-stats-increase' === type;

	let layout = 'mdc-layout-grid__cell--span-12';
	if ( 'large' === format ) {
		layout = 'mdc-layout-grid__cell--order-2-phone ' +
				'mdc-layout-grid__cell--order-1-tablet ' +
				'mdc-layout-grid__cell--span-6-tablet ' +
				'mdc-layout-grid__cell--span-8-desktop ';

		if ( inlineLayout ) {
			layout = 'mdc-layout-grid__cell--order-2-phone ' +
						'mdc-layout-grid__cell--order-1-tablet ' +
						'mdc-layout-grid__cell--span-5-tablet ' +
						'mdc-layout-grid__cell--span-8-desktop ';
		}
	} else if ( 'small' === format ) {
		layout = 'mdc-layout-grid__cell--span-11-desktop ' +
				'mdc-layout-grid__cell--span-7-tablet ' +
				'mdc-layout-grid__cell--span-3-phone';
	}

	let icon;
	if ( 'win-warning' === type ) {
		icon = <Warning />;
	} else if ( 'win-error' === type ) {
		icon = <Error />;
	} else {
		icon = '';
	}

	const dataBlockMarkup = (
		<Fragment>
			{ blockData &&

				{
					map( blockData, ( block, i ) => {
						return (

									<DataBlock { ...block } />

						);
					} )
				}

			}
		</Fragment>
	);

	const inlineMarkup = (
		<Fragment>
			{ title &&

				{ title }

			}
			{ anchorLink && anchorLinkLabel &&

				<Link href={ anchorLink }>
					{ anchorLinkLabel }
				</Link>

			}
			{ description &&

					{ isValidElement( description ) ? description : (

					) }

					{ learnMoreLabel &&
					<Fragment>
						{ ' ' }
						<Link href={ learnMoreURL } external inherit>
							{ learnMoreLabel }
						</Link>
						{ learnMoreDescription }
					</Fragment>
					}
					{ pageIndex &&
					{ pageIndex }
					}

			}
			{ children }
		</Fragment>
	);

	const logoSVG = module
		? <ModuleIcon slug={ module } size={ 19 } />
		: <GoogleLogoIcon height="34" width="32" />;

	return (
		<section
			id={ id }
			ref={ cardRef }
			className={ classnames(
				className,
				'googlesitekit-publisher-win',
				{
					[ `googlesitekit-publisher-win--${ format }` ]: format,
					[ `googlesitekit-publisher-win--${ type }` ]: type,
					[ `googlesitekit-publisher-win--${ closedClass }` ]: closedClass,
				},
			) }
		>

					{ logo &&

							{ logoSVG }

						{ moduleName &&

							{ moduleName }

						}

					}

					{ SmallImageSVG &&

						<SmallImageSVG />

					}

						{ inlineLayout ? (

									{ inlineMarkup }

									{ dataBlockMarkup }

						) : (
							<Fragment>
								{ inlineMarkup }
								{ dataBlockMarkup }
							</Fragment>
						) }

						{ ctaLink &&
						<Button
							className="googlesitekit-notification__cta"
							href={ ctaLink }
							target={ ctaTarget }
							onClick={ handleCTAClick }
						>
							{ ctaLabel }
						</Button>
						}

						{ isDismissable && dismiss &&
						<Link onClick={ handleDismiss }>
							{ dismiss }
						</Link>
						}

					{ WinImageSVG &&

							<WinImageSVG />

					}

					{ ( 'win-error' === type || 'win-warning' === type ) &&

							{ icon }

					}

	);
}

Notification.propTypes = {
	id: PropTypes.string.isRequired,
	className: PropTypes.string,
	title: PropTypes.string.isRequired,
	description: PropTypes.node,
	learnMoreURL: PropTypes.string,
	learnMoreDescription: PropTypes.string,
	learnMoreLabel: PropTypes.string,
	blockData: PropTypes.array,
	WinImageSVG: PropTypes.elementType,
	SmallImageSVG: PropTypes.elementType,
	format: PropTypes.string,
	ctaLink: PropTypes.string,
	ctaLabel: PropTypes.string,
	type: PropTypes.string,
	dismiss: PropTypes.string,
	isDismissable: PropTypes.bool,
	logo: PropTypes.bool,
	module: PropTypes.string,
	moduleName: PropTypes.string,
	pageIndex: PropTypes.string,
	dismissExpires: PropTypes.number,
	showOnce: PropTypes.bool,
	onCTAClick: PropTypes.func,
	onDismiss: PropTypes.func,
	anchorLink: PropTypes.string,
	anchorLinkLabel: PropTypes.string,
};

Notification.defaultProps = {
	isDismissable: true,
	className: '',
	dismissExpires: 0,
	showOnce: false,
};

export default Notification;
<|endoftext|>


<commit_before>
var debug = require('debug')('behringer');

/**
 *
 * @param {number} channel_number
 * @param {Behringer} connection
 * @returns {Channel}
 */
function Channel(channel_number, connection) {
    this.channel = channel_number - 1;
    this.connection = connection;
};

Channel.prototype.setAuxSend = function(aux_ch, db) {
    // aux1=70, aux2=72, ...
    var parameterNumber = ((aux_ch - 1) * 2) + 70;
    var dBValue = this.fullrangeValue(db);
    var sysex = this.paramChange(parameterNumber, dBValue);
    this.connection.sendCommand(sysex);
};

Channel.prototype.setAuxPre = function(aux_ch, isPre) {
    // pre-post aux1=71, aux2=73, ...
    var parameterNumber = ((aux_ch - 1) * 2) + 71;
    var sysex = this.paramChange(parameterNumber, isPre ? 1 : 0);
    this.connection.sendCommand(sysex);
};

Channel.prototype.setVolume = function(dB) {
    var sysex = this.paramChange(1, this.fullrangeValue(dB));
    this.connection.sendCommand(sysex);
}

Channel.prototype.fullrangeValue = function(db_fraction) {
    var unboundedValue = Math.round((db_fraction + 80) * 16);
    // clamp to 0-1472
    var parameterValue = Math.max(0, Math.min(unboundedValue, 1472));
    return parameterValue;
};

Channel.prototype.paramChange = function(parameter, parameterValue) {
    var sysex = [];
    sysex.push(0x20); // function code, 20 = parameter change
    sysex.push(1); // number of parameter changes (up to 23)
    sysex.push(this.channel);
    sysex.push(parameter);
    var low7bit  = parameterValue & 0x7F;
    var high7bit = (parameterValue >>> 7) & 0x7F;
    sysex.push(high7bit, low7bit);
    return sysex;
};

/**
 *
 * @param {any} out
 * @param {number} deviceChannel
 * @returns {Behringer}
 */
function Behringer(out, deviceChannel) {
    this.midi_out = out;
    Behringer.prototype.setDeviceChannel.apply(this, deviceChannel);
};

Behringer.prototype.setDeviceChannel = function(channel) {
    // 0ab0 cccc; a=ignore AppID, b=ignore Channel, c=Channel
    if (channel === undefined) {
        this.deviceByte = 0x60; // ignore appID, ignore channel
    } else {
        var highNibble  = 0x40; // ignore appID
        var lowNibble   = channel & 0x0F;
        this.deviceByte = highNibble | lowNibble;
    }
};

Behringer.prototype.channel = function(channel_number) {
    return new Channel(channel_number, this);
};

Behringer.prototype.sendCommand = function (commandBytes) {
    var sysexBytes = this.assembleCommand(commandBytes);
    debug("Sending SysEx:", sysexBytes.map(function(n){return n.toString(16);}));
    this.midi_out.sendMessage(sysexBytes);
};

Behringer.prototype.assembleCommand = function(commandBytes) {
    var sysex = [];
    sysex.push(0xF0); // sysex
    sysex.push(0x00); // for manufacurer
    sysex.push(0x20, 0x32); // Behringer
    sysex.push(this.deviceByte);
    sysex.push(0x0B); // device, DDX3216
    for (var byte in commandBytes) {
        sysex.push(commandBytes[byte]);
    }
    sysex.push(0xF7);
    return sysex;
};

module.exports = exports = Behringer;
<commit_msg>behringer.js: add "ping" command (as per Sysex doc)<commit_after>
var debug = require('debug')('behringer');

/**
 *
 * @param {number} channel_number
 * @param {Behringer} connection
 * @returns {Channel}
 */
function Channel(channel_number, connection) {
    this.channel = channel_number - 1;
    this.connection = connection;
};

Channel.prototype.setAuxSend = function(aux_ch, db) {
    // aux1=70, aux2=72, ...
    var parameterNumber = ((aux_ch - 1) * 2) + 70;
    var dBValue = this.fullrangeValue(db);
    var sysex = this.paramChange(parameterNumber, dBValue);
    this.connection.sendCommand(sysex);
};

Channel.prototype.setAuxPre = function(aux_ch, isPre) {
    // pre-post aux1=71, aux2=73, ...
    var parameterNumber = ((aux_ch - 1) * 2) + 71;
    var sysex = this.paramChange(parameterNumber, isPre ? 1 : 0);
    this.connection.sendCommand(sysex);
};

Channel.prototype.setVolume = function(dB) {
    var sysex = this.paramChange(1, this.fullrangeValue(dB));
    this.connection.sendCommand(sysex);
}

Channel.prototype.fullrangeValue = function(db_fraction) {
    var unboundedValue = Math.round((db_fraction + 80) * 16);
    // clamp to 0-1472
    var parameterValue = Math.max(0, Math.min(unboundedValue, 1472));
    return parameterValue;
};

Channel.prototype.paramChange = function(parameter, parameterValue) {
    var sysex = [];
    sysex.push(0x20); // function code, 20 = parameter change
    sysex.push(1); // number of parameter changes (up to 23)
    sysex.push(this.channel);
    sysex.push(parameter);
    var low7bit  = parameterValue & 0x7F;
    var high7bit = (parameterValue >>> 7) & 0x7F;
    sysex.push(high7bit, low7bit);
    return sysex;
};

/**
 *
 * @param {any} out
 * @param {number} deviceChannel
 * @returns {Behringer}
 */
function Behringer(out, deviceChannel) {
    this.midi_out = out;
    Behringer.prototype.setDeviceChannel.apply(this, deviceChannel);
};

Behringer.prototype.setDeviceChannel = function(channel) {
    // 0ab0 cccc; a=ignore AppID, b=ignore Channel, c=Channel
    if (channel === undefined) {
        this.deviceByte = 0x60; // ignore appID, ignore channel
    } else {
        var highNibble  = 0x40; // ignore appID
        var lowNibble   = channel & 0x0F;
        this.deviceByte = highNibble | lowNibble;
    }
};

Behringer.prototype.channel = function(channel_number) {
    return new Channel(channel_number, this);
};

Behringer.prototype.ping = function() {
    this.sendCommand(this.assembleCommand([0x40]));
}

Behringer.prototype.sendCommand = function (commandBytes) {
    var sysexBytes = this.assembleCommand(commandBytes);
    debug("Sending SysEx:", sysexBytes.map(function(n){return n.toString(16);}));
    this.midi_out.sendMessage(sysexBytes);
};

Behringer.prototype.assembleCommand = function(commandBytes) {
    var sysex = [];
    sysex.push(0xF0); // sysex
    sysex.push(0x00); // for manufacurer
    sysex.push(0x20, 0x32); // Behringer
    sysex.push(this.deviceByte);
    sysex.push(0x0B); // device, DDX3216
    for (var byte in commandBytes) {
        sysex.push(commandBytes[byte]);
    }
    sysex.push(0xF7);
    return sysex;
};

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


<commit_before>import path from 'path';
import webpack from 'webpack';
import ManifestPlugin from 'webpack-manifest-plugin';
import TerserJSPlugin from 'terser-webpack-plugin';
import OptimizeCSSAssetsPlugin from 'optimize-css-assets-webpack-plugin';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import CompressionPlugin from 'compression-webpack-plugin';
import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';
import FriendlyErrorsWebpackPlugin from 'friendly-errors-webpack-plugin';
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
import LoadablePlugin from '@loadable/webpack-plugin';

const nodeEnv = process.env.NODE_ENV || 'development';
const isDev = nodeEnv === 'development';

// Enable/disable css modules here
const USE_CSS_MODULES = true;

// Setup the plugins for development/production
const getPlugins = () => {
  // Common
  const plugins = [
    new ManifestPlugin({
      fileName: path.resolve(process.cwd(), 'public/webpack-assets.json'),
      filter: file => file.isInitial
    }),
    new LoadablePlugin({
      writeToDisk: true,
      filename: '../loadable-stats.json'
    }),
    new MiniCssExtractPlugin({
      // Don't use hash in development, we need the persistent for "renderHtml.js"
      filename: isDev ? '[name].css' : '[name].[contenthash:8].css',
      chunkFilename: isDev ? '[id].css' : '[id].[contenthash:8].css'
    }),
    // Setup enviorment variables for client
    new webpack.EnvironmentPlugin({ NODE_ENV: JSON.stringify(nodeEnv) }),
    // Setup global variables for client
    new webpack.DefinePlugin({
      __CLIENT__: true,
      __SERVER__: false,
      __DEV__: isDev
    })
  ];

  if (isDev) {
    // Development
    plugins.push(
      new webpack.HotModuleReplacementPlugin(),
      // Runs typescript type checker on a separate process
      new ForkTsCheckerWebpackPlugin(),
      new FriendlyErrorsWebpackPlugin()
    );
  } else {
    plugins.push(
      // Production
      new webpack.HashedModuleIdsPlugin(),
      new CompressionPlugin({
        test: /\.(js|css|html)$/,
        threshold: 10240
      }),
      // Visualize all of the webpack bundles
      // Check "https://github.com/webpack-contrib/webpack-bundle-analyzer#options-for-plugin"
      // for more configurations
      new BundleAnalyzerPlugin({
        analyzerMode: process.env.NODE_ENV === 'analyze' ? 'server' : 'disabled'
      })
    );
  }

  return plugins;
};

// Setup the entry for development/production
const getEntry = () => {
  // Development
  let entry = ['webpack-hot-middleware/client?reload=true', './src/client.tsx'];

  // production
  if (!isDev) entry = ['./src/client.tsx'];

  return entry;
};

// Webpack configuration
module.exports = {
  mode: isDev ? 'development' : 'production',
  devtool: isDev ? 'eval-source-map' : false,
  context: path.resolve(process.cwd()),
  entry: getEntry(),
  optimization: {
    minimizer: [
      new TerserJSPlugin({}),
      new OptimizeCSSAssetsPlugin({
        cssProcessorPluginOptions: {
          preset: ['default', { discardComments: { removeAll: !isDev } }]
        }
      })
    ],
    splitChunks: {
      // Auto split vendor modules in production only
      chunks: isDev ? 'async' : 'all'
    }
  },
  output: {
    path: path.resolve(process.cwd(), 'public/assets'),
    publicPath: '/assets/',
    // Don't use chunkhash in development it will increase compilation time
    filename: isDev ? '[name].js' : '[name].[chunkhash:8].js',
    chunkFilename: isDev ? '[id].js' : '[id].[chunkhash:8].js',
    pathinfo: isDev
  },
  module: {
    rules: [
      {
        test: /\.(t|j)sx?$/,
        exclude: /node_modules/,
        loader: 'babel',
        options: { cacheDirectory: isDev }
      },
      // All output '.js' files will have any sourcemaps re-processed by source-map-loader.
      // So you can debug your output code as if it was Typescript.
      {
        enforce: 'pre',
        test: /\.js$/,
        loader: 'source-map'
      },
      {
        test: /\.css$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              hmr: isDev,
              // If hmr does not work, this is a forceful method
              reloadAll: true
            }
          },
          {
            loader: 'css',
            options: {
              importLoaders: 1,
              modules: USE_CSS_MODULES && {
                localIdentName: isDev ? '[name]__[local]' : '[hash:base64:5]',
                context: path.resolve(process.cwd(), 'src')
              },
              sourceMap: true
            }
          },
          { loader: 'postcss', options: { sourceMap: true } }
        ]
      },
      {
        test: /\.(scss|sass)$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              hmr: isDev,
              reloadAll: true
            }
          },
          {
            loader: 'css',
            options: {
              importLoaders: 2,
              modules: USE_CSS_MODULES && {
                localIdentName: isDev ? '[name]__[local]' : '[hash:base64:5]',
                context: path.resolve(process.cwd(), 'src')
              },
              sourceMap: true
            }
          },
          { loader: 'postcss', options: { sourceMap: true } },
          { loader: 'sass', options: { sourceMap: true } }
        ]
      },
      {
        test: /\.(woff2?|ttf|otf|eot)$/,
        loader: 'file'
      },
      {
        test: /\.(gif|png|jpe?g|webp|svg)$/,
        use: [
          {
            // Any image below or equal to 10K will be converted to inline base64 instead
            loader: 'url',
            options: { limit: 10 * 1024, name: '[name].[hash:8].[ext]' }
          },
          {
            loader: 'image-webpack',
            // For each optimizer you wish to configure
            // Plz check https://github.com/tcoopman/image-webpack-loader#usage
            options: { disable: true }
          }
        ]
      }
    ]
  },
  plugins: getPlugins(),
  /* Advanced configuration */
  resolveLoader: {
    // Use loaders without the -loader suffix
    moduleExtensions: ['-loader']
  },
  resolve: {
    modules: ['src', 'node_modules'],
    descriptionFiles: ['package.json'],
    extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
    alias: { 'react-dom': '@hot-loader/react-dom' }
  },
  cache: isDev,
  // Some libraries import Node modules but don't use them in the browser.
  // Tell Webpack to provide empty mocks for them so importing them works.
  // https://webpack.github.io/docs/configuration.html#node
  // https://github.com/webpack/node-libs-browser/tree/master/mock
  node: {
    fs: 'empty',
    vm: 'empty',
    net: 'empty',
    tls: 'empty'
  }
};
<commit_msg>Chore(webpack): reuse loaders for CSS and SASS<commit_after>import path from 'path';
import webpack from 'webpack';
import ManifestPlugin from 'webpack-manifest-plugin';
import TerserJSPlugin from 'terser-webpack-plugin';
import OptimizeCSSAssetsPlugin from 'optimize-css-assets-webpack-plugin';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import CompressionPlugin from 'compression-webpack-plugin';
import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';
import FriendlyErrorsWebpackPlugin from 'friendly-errors-webpack-plugin';
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
import LoadablePlugin from '@loadable/webpack-plugin';

const nodeEnv = process.env.NODE_ENV || 'development';
const isDev = nodeEnv === 'development';

// Enable/disable css modules here
const USE_CSS_MODULES = true;

// Setup the plugins for development/production
const getPlugins = () => {
  // Common
  const plugins = [
    new ManifestPlugin({
      fileName: path.resolve(process.cwd(), 'public/webpack-assets.json'),
      filter: file => file.isInitial
    }),
    new LoadablePlugin({
      writeToDisk: true,
      filename: '../loadable-stats.json'
    }),
    new MiniCssExtractPlugin({
      // Don't use hash in development, we need the persistent for "renderHtml.js"
      filename: isDev ? '[name].css' : '[name].[contenthash:8].css',
      chunkFilename: isDev ? '[id].css' : '[id].[contenthash:8].css'
    }),
    // Setup enviorment variables for client
    new webpack.EnvironmentPlugin({ NODE_ENV: JSON.stringify(nodeEnv) }),
    // Setup global variables for client
    new webpack.DefinePlugin({
      __CLIENT__: true,
      __SERVER__: false,
      __DEV__: isDev
    })
  ];

  if (isDev) {
    // Development
    plugins.push(
      new webpack.HotModuleReplacementPlugin(),
      // Runs typescript type checker on a separate process
      new ForkTsCheckerWebpackPlugin(),
      new FriendlyErrorsWebpackPlugin()
    );
  } else {
    plugins.push(
      // Production
      new webpack.HashedModuleIdsPlugin(),
      new CompressionPlugin({
        test: /\.(js|css|html)$/,
        threshold: 10240
      }),
      // Visualize all of the webpack bundles
      // Check "https://github.com/webpack-contrib/webpack-bundle-analyzer#options-for-plugin"
      // for more configurations
      new BundleAnalyzerPlugin({
        analyzerMode: process.env.NODE_ENV === 'analyze' ? 'server' : 'disabled'
      })
    );
  }

  return plugins;
};

// Setup the entry for development/production
const getEntry = () => {
  // Development
  let entry = ['webpack-hot-middleware/client?reload=true', './src/client.tsx'];

  // production
  if (!isDev) entry = ['./src/client.tsx'];

  return entry;
};

// Loaders for CSS and SASS
const getStyleLoaders = (sass = false) => {
  const loaders = [
    {
      loader: MiniCssExtractPlugin.loader,
      options: {
        hmr: isDev,
        // If hmr does not work, this is a forceful method
        reloadAll: true
      }
    },
    {
      loader: 'css',
      options: {
        importLoaders: sass ? 2 : 1,
        modules: USE_CSS_MODULES && {
          localIdentName: isDev ? '[name]__[local]' : '[hash:base64:5]',
          context: path.resolve(process.cwd(), 'src')
        },
        sourceMap: true
      }
    },
    { loader: 'postcss', options: { sourceMap: true } }
  ];
  if (sass) loaders.push({ loader: 'sass', options: { sourceMap: true } });

  return loaders;
};

// Webpack configuration
module.exports = {
  mode: isDev ? 'development' : 'production',
  devtool: isDev ? 'eval-source-map' : false,
  context: path.resolve(process.cwd()),
  entry: getEntry(),
  optimization: {
    minimizer: [
      new TerserJSPlugin({}),
      new OptimizeCSSAssetsPlugin({
        cssProcessorPluginOptions: {
          preset: ['default', { discardComments: { removeAll: !isDev } }]
        }
      })
    ],
    splitChunks: {
      // Auto split vendor modules in production only
      chunks: isDev ? 'async' : 'all'
    }
  },
  output: {
    path: path.resolve(process.cwd(), 'public/assets'),
    publicPath: '/assets/',
    // Don't use chunkhash in development it will increase compilation time
    filename: isDev ? '[name].js' : '[name].[chunkhash:8].js',
    chunkFilename: isDev ? '[id].js' : '[id].[chunkhash:8].js',
    pathinfo: isDev
  },
  module: {
    rules: [
      {
        test: /\.(t|j)sx?$/,
        exclude: /node_modules/,
        loader: 'babel',
        options: { cacheDirectory: isDev }
      },
      // All output '.js' files will have any sourcemaps re-processed by source-map-loader.
      // So you can debug your output code as if it was Typescript.
      {
        enforce: 'pre',
        test: /\.js$/,
        loader: 'source-map'
      },
      {
        test: /\.css$/,
        use: getStyleLoaders()
      },
      {
        test: /\.(scss|sass)$/,
        use: getStyleLoaders(true)
      },
      {
        test: /\.(woff2?|ttf|otf|eot)$/,
        loader: 'file'
      },
      {
        test: /\.(gif|png|jpe?g|webp|svg)$/,
        use: [
          {
            // Any image below or equal to 10K will be converted to inline base64 instead
            loader: 'url',
            options: { limit: 10 * 1024, name: '[name].[hash:8].[ext]' }
          },
          {
            loader: 'image-webpack',
            // For each optimizer you wish to configure
            // Plz check https://github.com/tcoopman/image-webpack-loader#usage
            options: { disable: true }
          }
        ]
      }
    ]
  },
  plugins: getPlugins(),
  /* Advanced configuration */
  resolveLoader: {
    // Use loaders without the -loader suffix
    moduleExtensions: ['-loader']
  },
  resolve: {
    modules: ['src', 'node_modules'],
    descriptionFiles: ['package.json'],
    extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
    alias: { 'react-dom': '@hot-loader/react-dom' }
  },
  cache: isDev,
  // Some libraries import Node modules but don't use them in the browser.
  // Tell Webpack to provide empty mocks for them so importing them works.
  // https://webpack.github.io/docs/configuration.html#node
  // https://github.com/webpack/node-libs-browser/tree/master/mock
  node: {
    fs: 'empty',
    vm: 'empty',
    net: 'empty',
    tls: 'empty'
  }
};
<|endoftext|>


<commit_before>'use strict'
/**
 * Created by tungtouch on 2/9/15.
 */

var cluster = require('cluster');
var numCPUs = require('os').cpus().length;

var dgram = require('dgram');
var message = new Buffer("Some bytes hello world bo bo bo world HEHEHEHE ahhaha hohoho hehe:");
var client = dgram.createSocket("udp4");
var async = require('async');

var max = 10000;
var arr = [];

for (var i = 0; i < max; i++) {
    arr.push(i);
}

console.log("Num CPU:", numCPUs);

var q = async.queue(function(index, cb){
    setTimeout(function () {
        client.send(message, 0, message.length, 4444, "128.199.126.250", function (err) {
            console.log("Request : ", index);
            if(err){
                console.log('ERROR :', err);
            }
            cb(err);
        });
    }, 20);
});

if (cluster.isMaster) {
    // Fork workers.
    for (var i = 0; i < 100; i++) {
        cluster.fork();
    }

    cluster.on('exit', function(worker, code, signal) {
        console.log('worker ' + worker.process.pid + ' died');
    });
} else {
    // Workers can share any TCP connection
    // In this case its a HTTP server
    q.push(arr);
}
console.log("Starting Benchmark!");
<commit_msg>Update UDPefef<commit_after>'use strict'
/**
 * Created by tungtouch on 2/9/15.
 */

var cluster = require('cluster');
var numCPUs = require('os').cpus().length;

var dgram = require('dgram');
var message = new Buffer("Some bytes hello world bo bo bo world HEHEHEHE ahhaha hohoho hehe:");
var client = dgram.createSocket("udp4");
var async = require('async');

var max = 10000;
var arr = [];

for (var i = 0; i < max; i++) {
    arr.push(i);
}

console.log("Num CPU:", numCPUs);

var q = async.queue(function(index, cb){
    setTimeout(function () {
        client.send(message, 0, message.length, 4444, "128.199.126.250", function (err) {
            console.log("Request : ", index);
            if(err){
                console.log('ERROR :', err);
            }
            cb(err);
        });
    }, 20);
});

if (cluster.isMaster) {
    // Fork workers.
    for (var i = 0; i < 80; i++) {
        cluster.fork();
    }

    cluster.on('exit', function(worker, code, signal) {
        console.log('worker ' + worker.process.pid + ' died');
    });
} else {
    // Workers can share any TCP connection
    // In this case its a HTTP server
    q.push(arr);
}
console.log("Starting Benchmark!");
<|endoftext|>


<commit_before>/**
 * Utilities for the greenweb add-on
 *
 * @author Arend-Jan Tetteroo <aj@thegreenwebfoundation.org>
 * @copyright Cleanbits/The Green Web Foundation 2010-2014
 */

/**
 * Get the url from the given location
 */
function getUrl(loc)
{
    loc = this.stripProtocolFromUrl(loc);
    if(loc == false){
        return false;
    }
    loc = this.stripQueryStringFromUrl(loc);
    loc = this.stripPageFromUrl(loc);
    loc = this.stripPortFromUrl(loc);

    // Don't lookup localhost
    if(loc == 'localhost'){
        return false;
    }

    return loc;
}

/**
 * Strip the protocol from the location
 * If no http or https given, then return false
 */
function stripProtocolFromUrl(loc)
{
    if(loc == undefined){
        return false;
    }

    var prot = loc.substring(0,5);
    if(prot == 'http:'){
        return loc.substring(7);
    }
    if(prot == 'https'){
        return loc.substring(8);
    }
    // No http or https, no lookup
    return false;
}

/**
 * Only use the domain.tld, not the querystring behind ? or #
 */
function stripQueryStringFromUrl(loc)
{
    var temp = loc.split('?');
    loc = temp[0];
    temp = loc.split('#');
    loc = temp[0];
    return loc;
}

/**
 * Only use the domain.tld, not the page
 */
function stripPageFromUrl(loc)
{
    var temp = loc.split('/');
    loc = temp[0];
    return loc;
}

/**
 * Only use the domain.tld, not the port
 */
function stripPortFromUrl(loc)
{
    var temp = loc.split(':');
    loc = temp[0];
    return loc;
}

/**
 * Get the image with a cleanbits link around it
 */
function getLinkImage(color,tooltip)
{
    var output = "";
    output += getImage(color) + "";
    return output;
}

function getLinkNode(color)
{
    var href = 'http://www.thegreenwebfoundation.org';
    var a    = $("", { href: href, class: 'TGWF-addon' })
                 .append($('', { src: getImagePath(color), style: 'width:16px; height:16px;border:none;'  } ));
    return a;
}

/**
 * Get the image element based on the color
 */
function getImage(color)
{
    return  "";
}

/**
 * Get the image element as a jquery Node
 *
 * @param color
 * @returns {*|jQuery|HTMLElement}
 */
function getImageNode(color)
{
    return $('', { style: 'width:16px; height:16px;border:none;', src: getImagePath(color)});
}

/**
 * Get the image path based on file
 */
function getImagePath(file)
{
    var icons = [];
    icons['green']         = chrome.runtime.getURL("/images/green20x20.gif");
    icons['grey']          = chrome.runtime.getURL("/images/grey20x20.gif");
    icons['greenquestion'] = chrome.runtime.getURL("/images/greenquestion20x20.gif");
    icons['greenfan']      = chrome.runtime.getURL("/images/greenfan20x20.gif");
    icons['greenhouse']    = chrome.runtime.getURL("/images/greenhouse20x20.gif");

     if(icons[file]){
        return icons[file];
    }

    iconPath = 'http://images.cleanbits.net/icons/' + file + "20x20.gif";
    return iconPath;
}

/**
 * Get the resulting image from the data as jquery dom node
 */
function getResultNode(data)
{
    icon = getIcon(data);
    return getLinkNode(icon);
}

/**
 * Get the icon based on the data
 */
function getIcon(data)
{
    if (data.green) {
        // Green
        if(data.icon) {
            // Special icon
            return data.icon;
        }
        return 'green';
    }

    if(data.data == false){
        // Not enough data for the domain, show question
        return 'greenquestion';
    }
    return 'grey';
}

/**
 * Get the title based on the data
 */
function getTitle(data)
{
    if(data.green) {
        // Green
        if(data.hostedby){
            // We know the hoster, show it
            return 'Sustainably hosted by ' + data.hostedby;
        }
        return 'is sustainably hosted';
    }

    if(data.data == false){
        // No data available, show help message
        return "No data available yet for this country domain. Wanna help? Contact us through www.thegreenwebfoundation.org";
    }

    // Data available, so show grey site
    return data.url + ' is hosted grey';

}

/**
 * Get the title based on the data
 */
function getTitleWithLink(data)
{
    if(!data){
        return '';
    }
    if (data.green) {
        if (data.hostedby) {
            return data.url + ' ' + '' + ' is sustainably hosted by ' + ' ' + data.hostedby + '';
        }
        return data.url + ' ' + 'is sustainably hosted';
    }
    if (data.data == false) {
        // No data available, show help message
        return "No data available yet for this country domain. Wanna help? Contact us through "  + " www.thegreenwebfoundation.org";
    }
    // Data available, so show grey site
    return data.url + ' ' + ' is hosted grey';
}<commit_msg>refactor(utils): cleanup code<commit_after>/**
 * Utilities for the greenweb add-on
 *
 * @author Arend-Jan Tetteroo <aj@thegreenwebfoundation.org>
 * @copyright Cleanbits/The Green Web Foundation 2010-2014
 */

/**
 * Get the url from the given location
 */
function getUrl(loc)
{
    loc = this.stripProtocolFromUrl(loc);
    if (loc === false) {
        return false;
    }
    loc = this.stripQueryStringFromUrl(loc);
    loc = this.stripPageFromUrl(loc);
    loc = this.stripPortFromUrl(loc);

    // Don't lookup localhost
    if (loc === 'localhost') {
        return false;
    }

    return loc;
}

/**
 * Strip the protocol from the location
 * If no http or https given, then return false
 */
function stripProtocolFromUrl(loc)
{
    if (loc === undefined) {
        return false;
    }

    var prot = loc.substring(0,5);
    if(prot === 'http:'){
        return loc.substring(7);
    }

    if(prot === 'https'){
        return loc.substring(8);
    }

    // No http or https, no lookup
    return false;
}

/**
 * Only use the domain.tld, not the querystring behind ? or #
 */
function stripQueryStringFromUrl(loc)
{
    var temp = loc.split('?');
    loc = temp[0];
    temp = loc.split('#');
    loc = temp[0];
    return loc;
}

/**
 * Only use the domain.tld, not the page
 */
function stripPageFromUrl(loc)
{
    var temp = loc.split('/');
    loc = temp[0];
    return loc;
}

/**
 * Only use the domain.tld, not the port
 */
function stripPortFromUrl(loc)
{
    var temp = loc.split(':');
    loc = temp[0];
    return loc;
}

/**
 * Get the image with a cleanbits link around it
 */
function getLinkImage(color,tooltip)
{
    var output = "";
    output += getImage(color) + "";
    return output;
}

function getLinkNode(color)
{
    var href = 'http://www.thegreenwebfoundation.org';
    return $("", { href: href, class: 'TGWF-addon' })
                 .append($('', { src: getImagePath(color), style: 'width:16px; height:16px;border:none;'  } ));
}

/**
 * Get the image element based on the color
 */
function getImage(color)
{
    return  "";
}

/**
 * Get the image element as a jquery Node
 *
 * @param color
 * @returns {*|jQuery|HTMLElement}
 */
function getImageNode(color)
{
    return $('', { style: 'width:16px; height:16px;border:none;', src: getImagePath(color)});
}

/**
 * Get the image path based on file
 */
function getImagePath(file)
{
    var icons = {};
    icons['green']         = chrome.runtime.getURL("/images/green20x20.gif");
    icons['grey']          = chrome.runtime.getURL("/images/grey20x20.gif");
    icons['greenquestion'] = chrome.runtime.getURL("/images/greenquestion20x20.gif");
    icons['greenfan']      = chrome.runtime.getURL("/images/greenfan20x20.gif");
    icons['greenhouse']    = chrome.runtime.getURL("/images/greenhouse20x20.gif");

     if (icons[file]) {
        return icons[file];
    }

    return 'http://images.cleanbits.net/icons/' + file + "20x20.gif";
}

/**
 * Get the resulting image from the data as jquery dom node
 */
function getResultNode(data)
{
    var icon = getIcon(data);
    return getLinkNode(icon);
}

/**
 * Get the icon based on the data
 */
function getIcon(data)
{
    if (data.green) {
        // Green
        if(data.icon) {
            // Special icon
            return data.icon;
        }
        return 'green';
    }

    if (data.data === false) {
        // Not enough data for the domain, show question
        return 'greenquestion';
    }
    return 'grey';
}

/**
 * Get the title based on the data
 */
function getTitle(data)
{
    if(data.green) {
        // Green
        if(data.hostedby){
            // We know the hoster, show it
            return 'Sustainably hosted by ' + data.hostedby;
        }
        return 'is sustainably hosted';
    }

    if (data.data === false) {
        // No data available, show help message
        return "No data available yet for this country domain. Wanna help? Contact us through www.thegreenwebfoundation.org";
    }

    // Data available, so show grey site
    return data.url + ' is hosted grey';

}

/**
 * Get the title based on the data
 */
function getTitleWithLink(data)
{
    if (!data) {
        return '';
    }
    if (data.green) {
        if (data.hostedby) {
            return data.url + ' ' + '' + ' is sustainably hosted by ' + ' ' + data.hostedby + '';
        }
        return data.url + ' ' + 'is sustainably hosted';
    }

    if (data.data === false) {
        // No data available, show help message
        return "No data available yet for this country domain. Wanna help? Contact us through "  + " www.thegreenwebfoundation.org";
    }

    // Data available, so show grey site
    return data.url + ' ' + ' is hosted grey';
}<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
(function (aGlobal) {
  Components.utils.import('resource://gre/modules/Services.jsm');

  var NoDelete = {
    get debug() {
      return Services.prefs.getBoolPref('extensions.no-delete@clear-code.com.debug');
    },

    log: function(aMessage) {
      if (!this.debug)
        return;

     Services.console.logStringMessage('[no-delete] '+aMessage);
    },

    getTargetFolder: function(aFolder) {
      var folders = aFolder ? [aFolder] :
                    gFolderTreeView ? gFolderTreeView.getSelectedFolders() : // messenger.xul
                    [gFolderDisplay.displayedFolder] ; // messageWindow.xul
      this.log('target folder: '+(folders.length ? folders[0].folderURL : 'no target'));
      return folders[0];
    },

    isEmpty: function(aFolder) {
      return !aFolder.hasSubFolders && aFolder.getTotalMessages(false) === 0;
    },

    isInTrash: function(aFolder) {
      this.log('isInTrash: '+(aFolder ? aFolder.folderURL : 'no target'));
      if (!aFolder)
        return false;

      this.log('  flags     : '+(aFolder.flags));
      this.log('  trash flag: '+(aFolder.flags & Ci.nsMsgFolderFlags.Trash));
      if (aFolder.flags & Ci.nsMsgFolderFlags.Trash)
        return true;

      return this.isInTrash(aFolder.parent);
    },

    isCommandDisabled: function(aCommand) {
      this.log('isCommandDisabled: '+aCommand);
      switch (aCommand) {
        case 'cmd_shiftDelete':
        case 'button_shiftDelete':
          return true;

        case 'cmd_delete':
        case 'button_delete':
        case 'cmd_deleteJunk':
          return this.isInTrash(this.getTargetFolder());
      }

      return false;
    },

    init: function() {
      window.__no_delete__goDoCommand = window.goDoCommand;
      window.goDoCommand = function(aCommand) {
        if (NoDelete.isCommandDisabled(aCommand))
          return;
        return window.__no_delete__goDoCommand.call(this, aCommand);
      };

      if ('FolderPaneController' in window) {
        FolderPaneController.__no_delete__supportsCommand = FolderPaneController.supportsCommand;
          FolderPaneController.supportsCommand = function(aCommand) {
          if (NoDelete.isCommandDisabled(aCommand))
            return false;
          return FolderPaneController.__no_delete__supportsCommand.call(this, aCommand);
        };

        FolderPaneController.__no_delete__isCommandEnabled = FolderPaneController.isCommandEnabled;
        FolderPaneController.isCommandEnabled = function(aCommand) {
          if (NoDelete.isCommandDisabled(aCommand))
            return false;
          return FolderPaneController.__no_delete__isCommandEnabled.call(this, aCommand);
        };
      }

      if ('DefaultController' in window) {
        DefaultController.__no_delete__supportsCommand = DefaultController.supportsCommand;
        DefaultController.supportsCommand = function(aCommand) {
          if (NoDelete.isCommandDisabled(aCommand))
            return false;
          return DefaultController.__no_delete__supportsCommand.call(this, aCommand);
        };

        DefaultController.__no_delete__isCommandEnabled = DefaultController.isCommandEnabled;
        DefaultController.isCommandEnabled = function(aCommand) {
          if (NoDelete.isCommandDisabled(aCommand))
            return false;
          return DefaultController.__no_delete__isCommandEnabled.call(this, aCommand);
        };

        DefaultController.__no_delete__doCommand = DefaultController.doCommand;
        DefaultController.doCommand = function(aCommand, aTab) {
          if (NoDelete.isCommandDisabled(aCommand))
            return false;
          return DefaultController.__no_delete__doCommand.call(this, aCommand, aTab);
        };
      }
    }
  };

  document.addEventListener('DOMContentLoaded', function onDOMContentLoaded(aEvent) {
    document.removeEventListener('DOMContentLoaded', onDOMContentLoaded);
    NoDelete.init();
  });

  aGlobal.NoDelete = NoDelete;
})(this);
<commit_msg>Disable "cmd_delete" for independent message window correctly<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
(function (aGlobal) {
  Components.utils.import('resource://gre/modules/Services.jsm');

  var NoDelete = {
    get debug() {
      return Services.prefs.getBoolPref('extensions.no-delete@clear-code.com.debug');
    },

    log: function(aMessage) {
      if (!this.debug)
        return;

     Services.console.logStringMessage('[no-delete] '+aMessage);
    },

    getTargetFolder: function(aFolder) {
      var folders = aFolder ? [aFolder] :
                    gFolderTreeView ? gFolderTreeView.getSelectedFolders() : // messenger.xul
                    [gFolderDisplay.displayedFolder] ; // messageWindow.xul
      this.log('target folder: '+(folders.length ? folders[0].folderURL : 'no target'));
      return folders[0];
    },

    isEmpty: function(aFolder) {
      return !aFolder.hasSubFolders && aFolder.getTotalMessages(false) === 0;
    },

    isInTrash: function(aFolder) {
      this.log('isInTrash: '+(aFolder ? aFolder.folderURL : 'no target'));
      if (!aFolder)
        return false;

      this.log('  flags     : '+(aFolder.flags));
      this.log('  trash flag: '+(aFolder.flags & Ci.nsMsgFolderFlags.Trash));
      if (aFolder.flags & Ci.nsMsgFolderFlags.Trash)
        return true;

      return this.isInTrash(aFolder.parent);
    },

    isCommandDisabled: function(aCommand) {
      this.log('isCommandDisabled: '+aCommand);
      switch (aCommand) {
        case 'cmd_shiftDelete':
        case 'button_shiftDelete':
          return true;

        case 'cmd_delete':
        case 'button_delete':
        case 'cmd_deleteJunk':
          return this.isInTrash(this.getTargetFolder());
      }

      return false;
    },

    init: function() {
      window.__no_delete__goDoCommand = window.goDoCommand;
      window.goDoCommand = function(aCommand) {
        if (NoDelete.isCommandDisabled(aCommand))
          return;
        return window.__no_delete__goDoCommand.call(this, aCommand);
      };

      if ('FolderPaneController' in window) {
        FolderPaneController.__no_delete__supportsCommand = FolderPaneController.supportsCommand;
          FolderPaneController.supportsCommand = function(aCommand) {
          if (NoDelete.isCommandDisabled(aCommand))
            return false;
          return FolderPaneController.__no_delete__supportsCommand.call(this, aCommand);
        };

        FolderPaneController.__no_delete__isCommandEnabled = FolderPaneController.isCommandEnabled;
        FolderPaneController.isCommandEnabled = function(aCommand) {
          if (NoDelete.isCommandDisabled(aCommand))
            return false;
          return FolderPaneController.__no_delete__isCommandEnabled.call(this, aCommand);
        };
      }

      if ('DefaultController' in window) {
        DefaultController.__no_delete__supportsCommand = DefaultController.supportsCommand;
        DefaultController.supportsCommand = function(aCommand) {
          if (NoDelete.isCommandDisabled(aCommand))
            return false;
          return DefaultController.__no_delete__supportsCommand.call(this, aCommand);
        };

        DefaultController.__no_delete__isCommandEnabled = DefaultController.isCommandEnabled;
        DefaultController.isCommandEnabled = function(aCommand) {
          if (NoDelete.isCommandDisabled(aCommand))
            return false;
          return DefaultController.__no_delete__isCommandEnabled.call(this, aCommand);
        };

        DefaultController.__no_delete__doCommand = DefaultController.doCommand;
        DefaultController.doCommand = function(aCommand, aTab) {
          if (NoDelete.isCommandDisabled(aCommand))
            return false;
          return DefaultController.__no_delete__doCommand.call(this, aCommand, aTab);
        };
      }

      if ('MessageWindowController' in window) {
        MessageWindowController.__no_delete__supportsCommand = MessageWindowController.supportsCommand;
        MessageWindowController.supportsCommand = function(aCommand) {
          if (NoDelete.isCommandDisabled(aCommand))
            return false;
          return MessageWindowController.__no_delete__supportsCommand.call(this, aCommand);
        };

        MessageWindowController.__no_delete__isCommandEnabled = MessageWindowController.isCommandEnabled;
        MessageWindowController.isCommandEnabled = function(aCommand) {
          if (NoDelete.isCommandDisabled(aCommand))
            return false;
          return MessageWindowController.__no_delete__isCommandEnabled.call(this, aCommand);
        };

        MessageWindowController.__no_delete__doCommand = MessageWindowController.doCommand;
        MessageWindowController.doCommand = function(aCommand, aTab) {
          if (NoDelete.isCommandDisabled(aCommand))
            return false;
          return MessageWindowController.__no_delete__doCommand.call(this, aCommand, aTab);
        };
      }
    }
  };

  document.addEventListener('DOMContentLoaded', function onDOMContentLoaded(aEvent) {
    document.removeEventListener('DOMContentLoaded', onDOMContentLoaded);
    NoDelete.init();
  });

  aGlobal.NoDelete = NoDelete;
})(this);
<|endoftext|>


<commit_before>import R from 'ramda'
import { useEffect } from 'react'

import { EVENT } from '@constant'
import { buildLog, dispatchEvent } from '@utils'

/* eslint-disable-next-line */
const log = buildLog('L:GlobalLayout')

let store = null

export const openDoraemon = () => store.openDoraemon()
/* eslint-disable no-unused-vars */
export const queryDoraemon = R.curry((data, e) =>
  dispatchEvent(EVENT.QUERY_DORAMON, { data })
)

// ###############################
// init & uninit
// ###############################
export const useInit = (_store, extra) => {
  useEffect(() => {
    store = _store

    // FIXME:  do not show body scrollbar on mac
    /* eslint-disable no-undef */
    OverlayScrollbars(document.querySelectorAll('body'), {
      // NOT WORK!
      // scrollbars: { autoHide: 'scroll', autoHideDelay: 500 },
    })

    const { online, media, platform } = extra
    store.markState({ online, media, platform })
  }, [_store, extra])
}
<commit_msg>fix(scollbar): cancle custom-scrollbar on body, too buggy<commit_after>import R from 'ramda'
import { useEffect } from 'react'

import { EVENT } from '@constant'
import { buildLog, dispatchEvent } from '@utils'

/* eslint-disable-next-line */
const log = buildLog('L:GlobalLayout')

let store = null

export const openDoraemon = () => store.openDoraemon()
/* eslint-disable no-unused-vars */
export const queryDoraemon = R.curry((data, e) =>
  dispatchEvent(EVENT.QUERY_DORAMON, { data })
)

// ###############################
// init & uninit
// ###############################
export const useInit = (_store, extra) => {
  useEffect(() => {
    store = _store

    // FIXME:  do not show body scrollbar on mac
    // plus this plugin will break antd's affix staff
    /* eslint-disable no-undef */
    // OverlayScrollbars(document.querySelectorAll('body'), {
    // NOT WORK!
    // scrollbars: { autoHide: 'scroll', autoHideDelay: 500 },
    // })

    const { online, media, platform } = extra
    store.markState({ online, media, platform })
  }, [_store, extra])
}
<|endoftext|>


<commit_before>const languages = [
  {
    enabled: true,
    name: 'English',
    tag: 'en',
  },
  {
    enabled: false,
    name: '日本語',
    tag: 'ja',
  },
  {
    enabled: false,
    name: 'العربية',
    tag: 'ar',
  },
  {
    enabled: false,
    name: 'Bosanski',
    tag: 'bs-BA',
  },
  {
    enabled: true,
    name: 'Català',
    tag: 'ca',
  },
  {
    enabled: true,
    name: 'Čeština',
    tag: 'cs',
  },
  {
    enabled: false,
    name: 'Dansk',
    tag: 'da',
  },
  {
    enabled: true,
    name: 'Deutsch',
    tag: 'de',
  },
  {
    enabled: false,
    name: 'Ελληνικά',
    tag: 'el',
  },
  {
    enabled: true,
    name: 'Español',
    tag: 'es-ES',
  },
  {
    enabled: false,
    name: 'فارسی',
    tag: 'fa-IR',
  },
  {
    enabled: false,
    name: 'Suomi',
    tag: 'fi',
  },
  {
    enabled: true,
    name: 'Français',
    tag: 'fr',
  },
  {
    enabled: false,
    name: 'עִברִית',
    tag: 'he',
  },
  {
    enabled: false,
    name: 'Magyar',
    tag: 'hu',
  },
  {
    enabled: false,
    name: 'Bahasa Indonesia',
    tag: 'id-ID',
  },
  {
    enabled: false,
    name: 'Italiano',
    tag: 'it',
  },
  {
    enabled: false,
    name: 'Afrikaans',
    tag: 'af',
  },
  {
    enabled: false,
    name: '한국어',
    tag: 'ko',
  },
  {
    enabled: false,
    name: 'मराठी',
    tag: 'mr-IN',
  },
  {
    enabled: false,
    name: 'Nederlands',
    tag: 'nl',
  },
  {
    enabled: false,
    name: 'Norsk',
    tag: 'no-NO',
  },
  {
    enabled: false,
    name: 'Polskie',
    tag: 'pl',
  },
  {
    enabled: false,
    name: 'Português',
    tag: 'pt-PT',
  },
  {
    enabled: false,
    name: 'Português (Brasil)',
    tag: 'pt-BR',
  },
  {
    enabled: false,
    name: 'Română',
    tag: 'ro',
  },
  {
    enabled: true,
    name: 'Русский',
    tag: 'ru',
  },
  {
    enabled: false,
    name: 'Slovenský',
    tag: 'sk-SK',
  },
  {
    enabled: false,
    name: 'Српски језик (Ћирилица)',
    tag: 'sr',
  },
  {
    enabled: true,
    name: 'Svenska',
    tag: 'sv-SE',
  },
  {
    enabled: true,
    name: 'Türkçe',
    tag: 'tr',
  },
  {
    enabled: false,
    name: 'Українська',
    tag: 'uk',
  },
  {
    enabled: false,
    name: 'Tiếng Việt',
    tag: 'vi',
  },
  {
    enabled: true,
    name: '中文',
    tag: 'zh-CN',
  },
  {
    enabled: true,
    name: '繁體中文',
    tag: 'zh-TW',
  },
];
module.exports = languages;
<commit_msg>Enable languages (#218)<commit_after>const languages = [
  {
    enabled: true,
    name: 'English',
    tag: 'en',
  },
  {
    enabled: false,
    name: '日本語',
    tag: 'ja',
  },
  {
    enabled: true,
    name: 'العربية',
    tag: 'ar',
  },
  {
    enabled: false,
    name: 'Bosanski',
    tag: 'bs-BA',
  },
  {
    enabled: true,
    name: 'Català',
    tag: 'ca',
  },
  {
    enabled: true,
    name: 'Čeština',
    tag: 'cs',
  },
  {
    enabled: false,
    name: 'Dansk',
    tag: 'da',
  },
  {
    enabled: true,
    name: 'Deutsch',
    tag: 'de',
  },
  {
    enabled: false,
    name: 'Ελληνικά',
    tag: 'el',
  },
  {
    enabled: true,
    name: 'Español',
    tag: 'es-ES',
  },
  {
    enabled: false,
    name: 'فارسی',
    tag: 'fa-IR',
  },
  {
    enabled: false,
    name: 'Suomi',
    tag: 'fi',
  },
  {
    enabled: true,
    name: 'Français',
    tag: 'fr',
  },
  {
    enabled: false,
    name: 'עִברִית',
    tag: 'he',
  },
  {
    enabled: false,
    name: 'Magyar',
    tag: 'hu',
  },
  {
    enabled: false,
    name: 'Bahasa Indonesia',
    tag: 'id-ID',
  },
  {
    enabled: false,
    name: 'Italiano',
    tag: 'it',
  },
  {
    enabled: false,
    name: 'Afrikaans',
    tag: 'af',
  },
  {
    enabled: false,
    name: '한국어',
    tag: 'ko',
  },
  {
    enabled: false,
    name: 'मराठी',
    tag: 'mr-IN',
  },
  {
    enabled: false,
    name: 'Nederlands',
    tag: 'nl',
  },
  {
    enabled: false,
    name: 'Norsk',
    tag: 'no-NO',
  },
  {
    enabled: true,
    name: 'Polskie',
    tag: 'pl',
  },
  {
    enabled: false,
    name: 'Português',
    tag: 'pt-PT',
  },
  {
    enabled: false,
    name: 'Português (Brasil)',
    tag: 'pt-BR',
  },
  {
    enabled: false,
    name: 'Română',
    tag: 'ro',
  },
  {
    enabled: true,
    name: 'Русский',
    tag: 'ru',
  },
  {
    enabled: false,
    name: 'Slovenský',
    tag: 'sk-SK',
  },
  {
    enabled: false,
    name: 'Српски језик (Ћирилица)',
    tag: 'sr',
  },
  {
    enabled: true,
    name: 'Svenska',
    tag: 'sv-SE',
  },
  {
    enabled: true,
    name: 'Türkçe',
    tag: 'tr',
  },
  {
    enabled: false,
    name: 'Українська',
    tag: 'uk',
  },
  {
    enabled: false,
    name: 'Tiếng Việt',
    tag: 'vi',
  },
  {
    enabled: true,
    name: '中文',
    tag: 'zh-CN',
  },
  {
    enabled: true,
    name: '繁體中文',
    tag: 'zh-TW',
  },
];
module.exports = languages;
<|endoftext|>


<commit_before>'use strict';

var assert = require('assert');
var tasks = require('../task/09-functions-n-closures-tasks');
it.optional = require('../extensions/it-optional');

describe('09-functions-n-closures-tasks', function() {

    it.optional('getComposition should return the composition of two functions', () => {
        [
            { f:  Math.sin, g: Math.asin, arg: 0,  result: 0 },
            { f:  x=>x+1,   g: x=>x+1,    arg: 1,  result: 3 },
            { f:  x=>x*x,   g: x=>x+2,    arg: 5,  result: 49 },
        ].forEach(data => {
            var actual = tasks.getComposition(data.f, data.g);
            assert(
                actual(data.arg)==data.result
            )
        });
    });

    it.optional('getPowerFunction should return the math power function using the specified exponent', () => {

        var power2 = tasks.getPowerFunction(2);
        for(var i=0; i<10; i++) {
            assert.equal(power2(i), Math.pow(i,2));
        }

        var power05 = tasks.getPowerFunction(0.5);
        for(var i=0; i<10; i++) {
            assert.equal(power05(i), Math.pow(i, 0.5));
        }
    });

    it.optional('getPolynom should return the polynom with specified coefficients', () => {
        [
            {
                polynom: tasks.getPolynom(2,3,5),
                results: [ {x: 0, y: 5},  {x: 2, y: 19}, {x: 3, y: 32} ]
            },{
                polynom: tasks.getPolynom(1,-3),
                results: [ {x:0, y: -3}, {x:2, y: -1}, {x:5, y:2} ]
            },{
                polynom: tasks.getPolynom(8),
                results: [ {x:0, y:8},  {x:2, y:8},  {x:5, y:8} ]
            }
        ].forEach(data => {
            data.results.forEach(test => {
                assert(
                    test.y == data.polynom(test.x)
                )
            });
        });
    });

    it.optional('memoize method should cache the result of function', () => {
        var numberOfCalls = 0;
        var fn = function() {
            numberOfCalls++;
            return Math.random();
        }
        var memoizer = tasks.memoize(fn);
        var expected = memoizer();
        assert.equal(numberOfCalls, 1, 'memoize result should evaluate the specified function at first call');
        for(var i=0; i<10; i++) {
           let actual = memoizer();
           assert.equal(actual, expected, 'memoize result should return the cached value at second and next calls');
           assert.equal(numberOfCalls, 1, 'memoize result should not evaluate the specified function at second and next calls');
        }
    });

    it.optional('retry method should try to evaluate the specified function several times', () => {
        var maxAttemps = 3;
        var attemps = 0;
        var expected = 'expected';

        var fn = function() {
            if (attemps++<maxAttemps) throw new Error();
            return expected;
        }

        var actual = tasks.retry(fn, maxAttemps)();
        assert.equal(actual, expected);
    });

    it.optional('logger method should log start and end of call of the standard js function', () => {
        var log = '';

        var logFunc = (text) => ( log += text + '\n');
        var cosLogger = tasks.logger(Math.cos, logFunc);

        var actual = cosLogger(Math.PI);

        assert.equal(actual, -1, 'logger function should return the original result from specified function');
        assert.equal(
            log,
            'cos(3.141592653589793) starts\n'
           +'cos(3.141592653589793) ends\n',
            'logger function shoud log the start and end of the specified function');
    });

    it.optional('logger method should log start and end of call of the specified function', () => {
        var isCalling = false;
        var log = '';

        var fn = function testLogger(param, index) {
            assert.equal(
                log,
                'testLogger(["expected","test",1],0) starts\n',
                'logger function shoud log the start of specified function before calling'
            );
            isCalling = true;
            return param[index];
        }

        var logFunc = (text) => ( log += text + '\n');
        var logger = tasks.logger(fn, logFunc);

        var actual = logger(["expected", "test", 1], 0);

        assert.equal(isCalling, true, 'logger function should call the specified function');
        assert.equal(actual, 'expected', 'logger function should return the original result from specified function');
        assert.equal(
            log,
            'testLogger(["expected","test",1],0) starts\n'
           +'testLogger(["expected","test",1],0) ends\n',
            'logger function shoud log the end of specified function after calling');
    });

    it.optional('partialUsingArguments should return the function with partial applied arguments', () => {
        const fn = (x1,x2,x3,x4) => x1+x2+x3+x4;
        assert.equal(
            tasks.partialUsingArguments(fn, 'a')('b','c','d'),
            'abcd',
            "partialUsingArguments(fn, 'a')('b','c','d')' should return 'abcd'"
        );
        assert.equal(
            tasks.partialUsingArguments(fn, 'a','b')('c','d'),
            'abcd',
            "partialUsingArguments(fn, 'a','b')('c','d')' should return 'abcd'"
        );
        assert.equal(
            tasks.partialUsingArguments(fn, 'a','b','c')('d'),
            'abcd',
            "partialUsingArguments(fn, 'a','b','c')('d') should return 'abcd'"
        );
        assert.equal(
            tasks.partialUsingArguments(fn, 'a','b','c','d')(),
            'abcd',
            "partialUsingArguments(fn, 'a','b','c','d')()' should return 'abcd'"
        );
    });

    it.optional('getIdGeneratorFunction should return the id generator function', () => {

        var f0 = tasks.getIdGeneratorFunction(0);
        for(var i=0; i<1000; i++) {
            assert.equal(f0(), i);
        }

        var f10 = tasks.getIdGeneratorFunction(10);
        var f20 = tasks.getIdGeneratorFunction(20);
        for(var i=0; i<1000; i++) {
            assert.equal(f10(), 10+i);
            assert.equal(f20(), 20+i);
        }
    });

});
<commit_msg>fix wrong usage of increment operator<commit_after>'use strict';

var assert = require('assert');
var tasks = require('../task/09-functions-n-closures-tasks');
it.optional = require('../extensions/it-optional');

describe('09-functions-n-closures-tasks', function() {

    it.optional('getComposition should return the composition of two functions', () => {
        [
            { f:  Math.sin, g: Math.asin, arg: 0,  result: 0 },
            { f:  x=>x+1,   g: x=>x+1,    arg: 1,  result: 3 },
            { f:  x=>x*x,   g: x=>x+2,    arg: 5,  result: 49 },
        ].forEach(data => {
            var actual = tasks.getComposition(data.f, data.g);
            assert(
                actual(data.arg)==data.result
            )
        });
    });

    it.optional('getPowerFunction should return the math power function using the specified exponent', () => {

        var power2 = tasks.getPowerFunction(2);
        for(var i=0; i<10; i++) {
            assert.equal(power2(i), Math.pow(i,2));
        }

        var power05 = tasks.getPowerFunction(0.5);
        for(var i=0; i<10; i++) {
            assert.equal(power05(i), Math.pow(i, 0.5));
        }
    });

    it.optional('getPolynom should return the polynom with specified coefficients', () => {
        [
            {
                polynom: tasks.getPolynom(2,3,5),
                results: [ {x: 0, y: 5},  {x: 2, y: 19}, {x: 3, y: 32} ]
            },{
                polynom: tasks.getPolynom(1,-3),
                results: [ {x:0, y: -3}, {x:2, y: -1}, {x:5, y:2} ]
            },{
                polynom: tasks.getPolynom(8),
                results: [ {x:0, y:8},  {x:2, y:8},  {x:5, y:8} ]
            }
        ].forEach(data => {
            data.results.forEach(test => {
                assert(
                    test.y == data.polynom(test.x)
                )
            });
        });
    });

    it.optional('memoize method should cache the result of function', () => {
        var numberOfCalls = 0;
        var fn = function() {
            numberOfCalls++;
            return Math.random();
        }
        var memoizer = tasks.memoize(fn);
        var expected = memoizer();
        assert.equal(numberOfCalls, 1, 'memoize result should evaluate the specified function at first call');
        for(var i=0; i<10; i++) {
           let actual = memoizer();
           assert.equal(actual, expected, 'memoize result should return the cached value at second and next calls');
           assert.equal(numberOfCalls, 1, 'memoize result should not evaluate the specified function at second and next calls');
        }
    });

    it.optional('retry method should try to evaluate the specified function several times', () => {
        var maxAttemps = 3;
        var attemps = 0;
        var expected = 'expected';

        var fn = function() {
            if (++attemps<maxAttemps) throw new Error();
            return expected;
        }

        var actual = tasks.retry(fn, maxAttemps)();
        assert.equal(actual, expected);
    });

    it.optional('logger method should log start and end of call of the standard js function', () => {
        var log = '';

        var logFunc = (text) => ( log += text + '\n');
        var cosLogger = tasks.logger(Math.cos, logFunc);

        var actual = cosLogger(Math.PI);

        assert.equal(actual, -1, 'logger function should return the original result from specified function');
        assert.equal(
            log,
            'cos(3.141592653589793) starts\n'
           +'cos(3.141592653589793) ends\n',
            'logger function shoud log the start and end of the specified function');
    });

    it.optional('logger method should log start and end of call of the specified function', () => {
        var isCalling = false;
        var log = '';

        var fn = function testLogger(param, index) {
            assert.equal(
                log,
                'testLogger(["expected","test",1],0) starts\n',
                'logger function shoud log the start of specified function before calling'
            );
            isCalling = true;
            return param[index];
        }

        var logFunc = (text) => ( log += text + '\n');
        var logger = tasks.logger(fn, logFunc);

        var actual = logger(["expected", "test", 1], 0);

        assert.equal(isCalling, true, 'logger function should call the specified function');
        assert.equal(actual, 'expected', 'logger function should return the original result from specified function');
        assert.equal(
            log,
            'testLogger(["expected","test",1],0) starts\n'
           +'testLogger(["expected","test",1],0) ends\n',
            'logger function shoud log the end of specified function after calling');
    });

    it.optional('partialUsingArguments should return the function with partial applied arguments', () => {
        const fn = (x1,x2,x3,x4) => x1+x2+x3+x4;
        assert.equal(
            tasks.partialUsingArguments(fn, 'a')('b','c','d'),
            'abcd',
            "partialUsingArguments(fn, 'a')('b','c','d')' should return 'abcd'"
        );
        assert.equal(
            tasks.partialUsingArguments(fn, 'a','b')('c','d'),
            'abcd',
            "partialUsingArguments(fn, 'a','b')('c','d')' should return 'abcd'"
        );
        assert.equal(
            tasks.partialUsingArguments(fn, 'a','b','c')('d'),
            'abcd',
            "partialUsingArguments(fn, 'a','b','c')('d') should return 'abcd'"
        );
        assert.equal(
            tasks.partialUsingArguments(fn, 'a','b','c','d')(),
            'abcd',
            "partialUsingArguments(fn, 'a','b','c','d')()' should return 'abcd'"
        );
    });

    it.optional('getIdGeneratorFunction should return the id generator function', () => {

        var f0 = tasks.getIdGeneratorFunction(0);
        for(var i=0; i<1000; i++) {
            assert.equal(f0(), i);
        }

        var f10 = tasks.getIdGeneratorFunction(10);
        var f20 = tasks.getIdGeneratorFunction(20);
        for(var i=0; i<1000; i++) {
            assert.equal(f10(), 10+i);
            assert.equal(f20(), 20+i);
        }
    });

});
<|endoftext|>