<commit_before>/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 */

import type {InternalHasteMap} from 'types/HasteMap';
import type {CrawlerOptions} from '../types';

import normalizePathSep from '../lib/normalize_path_sep';
import path from 'path';
import watchman from 'fb-watchman';
import H from '../constants';

const watchmanURL =
  'https://facebook.github.io/watchman/docs/troubleshooting.html';

function WatchmanError(error: Error): Error {
  error.message =
    `Watchman error: ${error.message.trim()}. Make sure watchman ` +
    `is running for this project. See ${watchmanURL}.`;
  return error;
}

module.exports = async function watchmanCrawl(
  options: CrawlerOptions,
): Promise<InternalHasteMap> {
  const fields = ['name', 'exists', 'mtime_ms'];
  const {data, extensions, ignore, roots} = options;
  const defaultWatchExpression = [
    'allof',
    ['type', 'f'],
    ['anyof'].concat(extensions.map(extension => ['suffix', extension])),
  ];
  const clocks = data.clocks;
  const client = new watchman.Client();

  let clientError;
  client.on('error', error => (clientError = WatchmanError(error)));

  const cmd = (...args) =>
    new Promise((resolve, reject) =>
      client.command(
        args,
        (error, result) =>
          error ? reject(WatchmanError(error)) : resolve(result),
      ),
    );

  if (options.computeSha1) {
    const {capabilities} = await cmd('list-capabilities');

    if (capabilities.indexOf('field-content.sha1hex') !== -1) {
      fields.push('content.sha1hex');
    }
  }

  async function getWatchmanRoots(roots) {
    const watchmanRoots = new Map();
    await Promise.all(
      roots.map(async root => {
        const response = await cmd('watch-project', root);
        const existing = watchmanRoots.get(response.watch);
        // A root can only be filtered if it was never seen with a
        // relative_path before.
        const canBeFiltered = !existing || existing.length > 0;

        if (canBeFiltered) {
          if (response.relative_path) {
            watchmanRoots.set(
              response.watch,
              (existing || []).concat(response.relative_path),
            );
          } else {
            // Make the filter directories an empty array to signal that this
            // root was already seen and needs to be watched for all files or
            // directories.
            watchmanRoots.set(response.watch, []);
          }
        }
      }),
    );
    return watchmanRoots;
  }

  async function queryWatchmanForDirs(rootProjectDirMappings) {
    const files = new Map();
    let isFresh = false;
    await Promise.all(
      Array.from(rootProjectDirMappings).map(
        async ([root, directoryFilters]) => {
          const expression = Array.from(defaultWatchExpression);
          if (directoryFilters.length > 0) {
            expression.push([
              'anyof',
              ...directoryFilters.map(dir => ['dirname', dir]),
            ]);
          }

          const query = clocks[root]
            ? // Use the `since` generator if we have a clock available
              {expression, fields, since: clocks[root]}
            : // Otherwise use the `suffix` generator
              {expression, fields, suffix: extensions};

          const response = await cmd('query', root, query);

          if ('warning' in response) {
            console.warn('watchman warning: ', response.warning);
          }

          isFresh = isFresh || response.is_fresh_instance;
          files.set(root, response);
        },
      ),
    );

    return {
      files,
      isFresh,
    };
  }

  let files = data.files;
  let watchmanFiles;
  try {
    const watchmanRoots = await getWatchmanRoots(roots);
    const watchmanFileResults = await queryWatchmanForDirs(watchmanRoots);

    // Reset the file map if watchman was restarted and sends us a list of
    // files.
    if (watchmanFileResults.isFresh) {
      files = Object.create(null);
    }

    watchmanFiles = watchmanFileResults.files;
  } finally {
    client.end();
  }

  if (clientError) {
    throw clientError;
  }

  for (const [watchRoot, response] of watchmanFiles) {
    const fsRoot = normalizePathSep(watchRoot);
    clocks[fsRoot] = response.clock;
    for (const fileData of response.files) {
      const name = fsRoot + path.sep + normalizePathSep(fileData.name);
      if (!fileData.exists) {
        delete files[name];
      } else if (!ignore(name)) {
        const mtime =
          typeof fileData.mtime_ms === 'number'
            ? fileData.mtime_ms
            : fileData.mtime_ms.toNumber();
        const existingFileData = data.files[name];
        const isOld = existingFileData && existingFileData[H.MTIME] === mtime;
        if (isOld) {
          files[name] = existingFileData;
        } else {
          // See ../constants.js
          files[name] = ['', mtime, 0, [], fileData['content.sha1hex'] || null];
        }
      }
    }
  }

  data.files = files;
  return data;
};
<commit_msg>Ensure that watchman returned a SHA-1 (#6045)<commit_after>/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 */

import type {InternalHasteMap} from 'types/HasteMap';
import type {CrawlerOptions} from '../types';

import normalizePathSep from '../lib/normalize_path_sep';
import path from 'path';
import watchman from 'fb-watchman';
import H from '../constants';

const watchmanURL =
  'https://facebook.github.io/watchman/docs/troubleshooting.html';

function WatchmanError(error: Error): Error {
  error.message =
    `Watchman error: ${error.message.trim()}. Make sure watchman ` +
    `is running for this project. See ${watchmanURL}.`;
  return error;
}

module.exports = async function watchmanCrawl(
  options: CrawlerOptions,
): Promise<InternalHasteMap> {
  const fields = ['name', 'exists', 'mtime_ms'];
  const {data, extensions, ignore, roots} = options;
  const defaultWatchExpression = [
    'allof',
    ['type', 'f'],
    ['anyof'].concat(extensions.map(extension => ['suffix', extension])),
  ];
  const clocks = data.clocks;
  const client = new watchman.Client();

  let clientError;
  client.on('error', error => (clientError = WatchmanError(error)));

  const cmd = (...args) =>
    new Promise((resolve, reject) =>
      client.command(
        args,
        (error, result) =>
          error ? reject(WatchmanError(error)) : resolve(result),
      ),
    );

  if (options.computeSha1) {
    const {capabilities} = await cmd('list-capabilities');

    if (capabilities.indexOf('field-content.sha1hex') !== -1) {
      fields.push('content.sha1hex');
    }
  }

  async function getWatchmanRoots(roots) {
    const watchmanRoots = new Map();
    await Promise.all(
      roots.map(async root => {
        const response = await cmd('watch-project', root);
        const existing = watchmanRoots.get(response.watch);
        // A root can only be filtered if it was never seen with a
        // relative_path before.
        const canBeFiltered = !existing || existing.length > 0;

        if (canBeFiltered) {
          if (response.relative_path) {
            watchmanRoots.set(
              response.watch,
              (existing || []).concat(response.relative_path),
            );
          } else {
            // Make the filter directories an empty array to signal that this
            // root was already seen and needs to be watched for all files or
            // directories.
            watchmanRoots.set(response.watch, []);
          }
        }
      }),
    );
    return watchmanRoots;
  }

  async function queryWatchmanForDirs(rootProjectDirMappings) {
    const files = new Map();
    let isFresh = false;
    await Promise.all(
      Array.from(rootProjectDirMappings).map(
        async ([root, directoryFilters]) => {
          const expression = Array.from(defaultWatchExpression);
          if (directoryFilters.length > 0) {
            expression.push([
              'anyof',
              ...directoryFilters.map(dir => ['dirname', dir]),
            ]);
          }

          const query = clocks[root]
            ? // Use the `since` generator if we have a clock available
              {expression, fields, since: clocks[root]}
            : // Otherwise use the `suffix` generator
              {expression, fields, suffix: extensions};

          const response = await cmd('query', root, query);

          if ('warning' in response) {
            console.warn('watchman warning: ', response.warning);
          }

          isFresh = isFresh || response.is_fresh_instance;
          files.set(root, response);
        },
      ),
    );

    return {
      files,
      isFresh,
    };
  }

  let files = data.files;
  let watchmanFiles;
  try {
    const watchmanRoots = await getWatchmanRoots(roots);
    const watchmanFileResults = await queryWatchmanForDirs(watchmanRoots);

    // Reset the file map if watchman was restarted and sends us a list of
    // files.
    if (watchmanFileResults.isFresh) {
      files = Object.create(null);
    }

    watchmanFiles = watchmanFileResults.files;
  } finally {
    client.end();
  }

  if (clientError) {
    throw clientError;
  }

  for (const [watchRoot, response] of watchmanFiles) {
    const fsRoot = normalizePathSep(watchRoot);
    clocks[fsRoot] = response.clock;
    for (const fileData of response.files) {
      const name = fsRoot + path.sep + normalizePathSep(fileData.name);
      if (!fileData.exists) {
        delete files[name];
      } else if (!ignore(name)) {
        const mtime =
          typeof fileData.mtime_ms === 'number'
            ? fileData.mtime_ms
            : fileData.mtime_ms.toNumber();
        const existingFileData = data.files[name];
        const isOld = existingFileData && existingFileData[H.MTIME] === mtime;
        if (isOld) {
          files[name] = existingFileData;
        } else {
          let sha1hex = fileData['content.sha1hex'];

          if (typeof sha1hex !== 'string' || sha1hex.length !== 40) {
            sha1hex = null;
          }

          // See ../constants.js
          files[name] = ['', mtime, 0, [], sha1hex];
        }
      }
    }
  }

  data.files = files;
  return data;
};
<|endoftext|>


<commit_before><commit_msg>Simplify buffer type guessing<commit_after><|endoftext|>


<commit_before>const Sequelize = require('sequelize');
const fs = require('fs');
const path = require('path');
const {loadModels, PromiseUtils, HookIncrementVersionOnSave, HookTransactionLog} = require('isomorphic-core');
const TransactionConnector = require('./transaction-connector')

require('./database-extensions'); // Extends Sequelize on require

const ENABLE_SEQUELIZE_DEBUG_LOGGING = process.env.ENABLE_SEQUELIZE_DEBUG_LOGGING;

class LocalDatabaseConnector {
  constructor() {
    this._cache = {};
  }

  _sequelizePoolForDatabase(dbname) {
    const storage = NylasEnv.inSpecMode() ? ':memory:' : path.join(process.env.NYLAS_HOME, `${dbname}.sqlite`);
    return new Sequelize(dbname, '', '', {
      storage: storage,
      dialect: "sqlite",
      logging: ENABLE_SEQUELIZE_DEBUG_LOGGING ? console.log : false,
    })
  }

  forAccount(accountId) {
    if (!accountId) {
      return Promise.reject(new Error(`You need to pass an accountId to init the database!`))
    }

    if (this._cache[accountId]) {
      return this._cache[accountId];
    }

    const newSequelize = this._sequelizePoolForDatabase(`a-${accountId}`);
    const db = loadModels(Sequelize, newSequelize, {
      modelDirs: [path.resolve(__dirname, '..', 'models')],
    })

    HookTransactionLog(db, newSequelize, {
      onCreatedTransaction: (transaction) => {
        TransactionConnector.notifyDelta(db.accountId, transaction);
      },
    });

    HookIncrementVersionOnSave(db, newSequelize);

    db.sequelize = newSequelize;
    db.Sequelize = Sequelize;
    db.accountId = accountId;

    this._cache[accountId] = newSequelize.authenticate().thenReturn(db);

    return this._cache[accountId];
  }

  ensureAccountDatabase(accountId) {
    return this.forAccount(accountId).then((db) => {
      // this is a bit of a hack, because sequelize.sync() doesn't work with
      // schemas. It's necessary to sync models individually and in the right order.
      const models = ['Contact', 'Folder', 'Label', 'Transaction', 'Thread', 'ThreadLabel', 'ThreadFolder', 'Message', 'MessageLabel', 'Reference', 'MessageReference', 'File', 'SyncbackRequest'];
      return PromiseUtils.each(models, (n) =>
        db[n].sync()
      )
    });
  }

  destroyAccountDatabase(accountId) {
    if (NylasEnv.inSpecMode()) {
      // The db is in memory, so we don't have to unlink it. Just drop the data.
      return this.forAccount(accountId).then(db => {
        delete this._cache[accountId];
        return db.sequelize.drop()
      });
    }

    const dbname = `a-${accountId}`;
    const dbpath = path.join(process.env.NYLAS_HOME, `${dbname}.sqlite`);

    try {
      const err = fs.accessSync(dbpath, fs.F_OK);
      if (!err) {
        fs.unlinkSync(dbpath);
      }
    } catch (err) {
      // Ignored
    }

    delete this._cache[accountId];
    return Promise.resolve();
  }

  _sequelizeForShared() {
    const sequelize = this._sequelizePoolForDatabase(`shared`);
    const db = loadModels(Sequelize, sequelize)

    db.sequelize = sequelize;
    db.Sequelize = Sequelize;

    return sequelize.authenticate().then(() =>
      sequelize.sync()
    ).thenReturn(db);
  }

  forShared() {
    this._cache.shared = this._cache.shared || this._sequelizeForShared();
    return this._cache.shared;
  }
}

module.exports = new LocalDatabaseConnector()
<commit_msg>[client-sync] :art: Remove unecessary use of PromiseUtils<commit_after>const Sequelize = require('sequelize');
const fs = require('fs');
const path = require('path');
const {loadModels, HookIncrementVersionOnSave, HookTransactionLog} = require('isomorphic-core');
const TransactionConnector = require('./transaction-connector')

require('./database-extensions'); // Extends Sequelize on require

const ENABLE_SEQUELIZE_DEBUG_LOGGING = process.env.ENABLE_SEQUELIZE_DEBUG_LOGGING;

class LocalDatabaseConnector {
  constructor() {
    this._cache = {};
  }

  _sequelizePoolForDatabase(dbname) {
    const storage = NylasEnv.inSpecMode() ? ':memory:' : path.join(process.env.NYLAS_HOME, `${dbname}.sqlite`);
    return new Sequelize(dbname, '', '', {
      storage: storage,
      dialect: "sqlite",
      logging: ENABLE_SEQUELIZE_DEBUG_LOGGING ? console.log : false,
    })
  }

  forAccount(accountId) {
    if (!accountId) {
      return Promise.reject(new Error(`You need to pass an accountId to init the database!`))
    }

    if (this._cache[accountId]) {
      return this._cache[accountId];
    }

    const newSequelize = this._sequelizePoolForDatabase(`a-${accountId}`);
    const db = loadModels(Sequelize, newSequelize, {
      modelDirs: [path.resolve(__dirname, '..', 'models')],
    })

    HookTransactionLog(db, newSequelize, {
      onCreatedTransaction: (transaction) => {
        TransactionConnector.notifyDelta(db.accountId, transaction);
      },
    });

    HookIncrementVersionOnSave(db, newSequelize);

    db.sequelize = newSequelize;
    db.Sequelize = Sequelize;
    db.accountId = accountId;

    this._cache[accountId] = newSequelize.authenticate().thenReturn(db);

    return this._cache[accountId];
  }

  ensureAccountDatabase(accountId) {
    return this.forAccount(accountId).then((db) => {
      // this is a bit of a hack, because sequelize.sync() doesn't work with
      // schemas. It's necessary to sync models individually and in the right order.
      const models = ['Contact', 'Folder', 'Label', 'Transaction', 'Thread', 'ThreadLabel', 'ThreadFolder', 'Message', 'MessageLabel', 'Reference', 'MessageReference', 'File', 'SyncbackRequest'];
      return Promise.each(models, (n) =>
        db[n].sync()
      )
    });
  }

  destroyAccountDatabase(accountId) {
    if (NylasEnv.inSpecMode()) {
      // The db is in memory, so we don't have to unlink it. Just drop the data.
      return this.forAccount(accountId).then(db => {
        delete this._cache[accountId];
        return db.sequelize.drop()
      });
    }

    const dbname = `a-${accountId}`;
    const dbpath = path.join(process.env.NYLAS_HOME, `${dbname}.sqlite`);

    try {
      const err = fs.accessSync(dbpath, fs.F_OK);
      if (!err) {
        fs.unlinkSync(dbpath);
      }
    } catch (err) {
      // Ignored
    }

    delete this._cache[accountId];
    return Promise.resolve();
  }

  _sequelizeForShared() {
    const sequelize = this._sequelizePoolForDatabase(`shared`);
    const db = loadModels(Sequelize, sequelize)

    db.sequelize = sequelize;
    db.Sequelize = Sequelize;

    return sequelize.authenticate().then(() =>
      sequelize.sync()
    ).thenReturn(db);
  }

  forShared() {
    this._cache.shared = this._cache.shared || this._sequelizeForShared();
    return this._cache.shared;
  }
}

module.exports = new LocalDatabaseConnector()
<|endoftext|>


<commit_before>const uppercasePattern = /[A-Z]/g;
const msPattern = /^ms-/;

module.exports = hyphenateStyleName;

function hyphenateStyleName(prop) {
  return prop
    .replace(uppercasePattern, '-$&')
    .toLowerCase()
    .replace(msPattern, '-ms-');
}
<commit_msg>Added css property caching<commit_after>const uppercasePattern = /[A-Z]/g;
const msPattern = /^ms-/;
const cache = {};

module.exports = hyphenateStyleName;

function hyphenateStyleName(prop) {
  return prop in cache
    ? cache[prop]
    : cache[prop] = prop
      .replace(uppercasePattern, '-$&')
      .toLowerCase()
      .replace(msPattern, '-ms-');
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

'use strict';

/* eslint-disable no-for-of-loops/no-for-of-loops */

// Hi, if this is your first time editing/reading a Dangerfile, here's a summary:
// It's a JS runtime which helps you provide continuous feedback inside GitHub.
//
// You can see the docs here: http://danger.systems/js/
//
// If you want to test changes Danger, I'd recommend checking out an existing PR
// and then running the `danger pr` command.
//
// You'll need a GitHub token, you can re-use this one:
//
//  0a7d5c3cad9a6dbec2d9 9a5222cf49062a4c1ef7
//
// (Just remove the space)
//
// So, for example:
//
// `DANGER_GITHUB_API_TOKEN=[ENV_ABOVE] yarn danger pr https://github.com/facebook/react/pull/11865

const {markdown, danger, warn} = require('danger');
const {promisify} = require('util');
const glob = promisify(require('glob'));
const gzipSize = require('gzip-size');

const {readFileSync, statSync} = require('fs');

const BASE_DIR = 'base-build';
const HEAD_DIR = 'build';

const CRITICAL_THRESHOLD = 0.02;
const SIGNIFICANCE_THRESHOLD = 0.002;
const CRITICAL_ARTIFACT_PATHS = new Set([
  // We always report changes to these bundles, even if the change is
  // insignificant or non-existent.
  'oss-stable/react-dom/cjs/react-dom.production.min.js',
  'oss-experimental/react-dom/cjs/react-dom.production.min.js',
  'facebook-www/ReactDOM-prod.classic.js',
  'facebook-www/ReactDOM-prod.modern.js',
  'facebook-www/ReactDOMForked-prod.classic.js',
]);

const kilobyteFormatter = new Intl.NumberFormat('en', {
  style: 'unit',
  unit: 'kilobyte',
  minimumFractionDigits: 2,
  maximumFractionDigits: 2,
});

function kbs(bytes) {
  return kilobyteFormatter.format(bytes / 1000);
}

const percentFormatter = new Intl.NumberFormat('en', {
  style: 'percent',
  signDisplay: 'exceptZero',
  minimumFractionDigits: 2,
  maximumFractionDigits: 2,
});

function change(decimal) {
  if (Number === Infinity) {
    return 'New file';
  }
  if (decimal === -1) {
    return 'Deleted';
  }
  if (decimal < 0.0001) {
    return '=';
  }
  return percentFormatter.format(decimal);
}

const header = `
  | Name | +/- | Base | Current | +/- gzip | Base gzip | Current gzip |
  | ---- | --- | ---- | ------- | -------- | --------- | ------------ |`;

function row(result, baseSha, headSha) {
  const diffViewUrl = `https://react-builds.vercel.app/commits/${headSha}/files/${result.path}?compare=${baseSha}`;
  // prettier-ignore
  return `| [${result.path}](${diffViewUrl}) | **${change(result.change)}** | ${kbs(result.baseSize)} | ${kbs(result.headSize)} | ${change(result.changeGzip)} | ${kbs(result.baseSizeGzip)} | ${kbs(result.headSizeGzip)}`;
}

(async function() {
  // Use git locally to grab the commit which represents the place
  // where the branches differ

  const upstreamRepo = danger.github.pr.base.repo.full_name;
  if (upstreamRepo !== 'facebook/react') {
    // Exit unless we're running in the main repo
    return;
  }

  let headSha;
  let baseSha;
  try {
    headSha = String(readFileSync(HEAD_DIR + '/COMMIT_SHA')).trim();
    baseSha = String(readFileSync(BASE_DIR + '/COMMIT_SHA')).trim();
  } catch {
    warn(
      "Failed to read build artifacts. It's possible a build configuration " +
        'has changed upstream. Try pulling the latest changes from the ' +
        'main branch.'
    );
    return;
  }

  // Disable sizeBot in a Devtools Pull Request. Because that doesn't affect production bundle size.
  const commitFiles = [
    ...danger.git.created_files,
    ...danger.git.deleted_files,
    ...danger.git.modified_files,
  ];
  if (
    commitFiles.every(filename => filename.includes('packages/react-devtools'))
  )
    return;

  const resultsMap = new Map();

  // Find all the head (current) artifacts paths.
  const headArtifactPaths = await glob('**/*.js', {cwd: 'build'});
  for (const artifactPath of headArtifactPaths) {
    try {
      // This will throw if there's no matching base artifact
      const baseSize = statSync(BASE_DIR + '/' + artifactPath).size;
      const baseSizeGzip = gzipSize.fileSync(BASE_DIR + '/' + artifactPath);

      const headSize = statSync(HEAD_DIR + '/' + artifactPath).size;
      const headSizeGzip = gzipSize.fileSync(HEAD_DIR + '/' + artifactPath);
      resultsMap.set(artifactPath, {
        path: artifactPath,
        headSize,
        headSizeGzip,
        baseSize,
        baseSizeGzip,
        change: (headSize - baseSize) / baseSize,
        changeGzip: (headSizeGzip - baseSizeGzip) / baseSizeGzip,
      });
    } catch {
      // There's no matching base artifact. This is a new file.
      const baseSize = 0;
      const baseSizeGzip = 0;
      const headSize = statSync(HEAD_DIR + '/' + artifactPath).size;
      const headSizeGzip = gzipSize.fileSync(HEAD_DIR + '/' + artifactPath);
      resultsMap.set(artifactPath, {
        path: artifactPath,
        headSize,
        headSizeGzip,
        baseSize,
        baseSizeGzip,
        change: Infinity,
        changeGzip: Infinity,
      });
    }
  }

  // Check for base artifacts that were deleted in the head.
  const baseArtifactPaths = await glob('**/*.js', {cwd: 'base-build'});
  for (const artifactPath of baseArtifactPaths) {
    if (!resultsMap.has(artifactPath)) {
      const baseSize = statSync(BASE_DIR + '/' + artifactPath).size;
      const baseSizeGzip = gzipSize.fileSync(BASE_DIR + '/' + artifactPath);
      const headSize = 0;
      const headSizeGzip = 0;
      resultsMap.set(artifactPath, {
        path: artifactPath,
        headSize,
        headSizeGzip,
        baseSize,
        baseSizeGzip,
        change: -1,
        changeGzip: -1,
      });
    }
  }

  const results = Array.from(resultsMap.values());
  results.sort((a, b) => b.change - a.change);

  let criticalResults = [];
  for (const artifactPath of CRITICAL_ARTIFACT_PATHS) {
    const result = resultsMap.get(artifactPath);
    if (result === undefined) {
      throw new Error(
        'Missing expected bundle. If this was an intentional change to the ' +
          'build configuration, update Dangerfile.js accordingly: ' +
          artifactPath
      );
    }
    criticalResults.push(row(result, baseSha, headSha));
  }

  let significantResults = [];
  for (const result of results) {
    // If result exceeds critical threshold, add to top section.
    if (
      (result.change > CRITICAL_THRESHOLD ||
        0 - result.change > CRITICAL_THRESHOLD ||
        // New file
        result.change === Infinity ||
        // Deleted file
        result.change === -1) &&
      // Skip critical artifacts. We added those earlier, in a fixed order.
      !CRITICAL_ARTIFACT_PATHS.has(result.path)
    ) {
      criticalResults.push(row(result, baseSha, headSha));
    }

    // Do the same for results that exceed the significant threshold. These
    // will go into the bottom, collapsed section. Intentionally including
    // critical artifacts in this section, too.
    if (
      result.change > SIGNIFICANCE_THRESHOLD ||
      0 - result.change > SIGNIFICANCE_THRESHOLD ||
      result.change === Infinity ||
      result.change === -1
    ) {
      significantResults.push(row(result, baseSha, headSha));
    }
  }

  markdown(`
Comparing: ${baseSha}...${headSha}

## Critical size changes

Includes critical production bundles, as well as any change greater than ${CRITICAL_THRESHOLD *
    100}%:

${header}
${criticalResults.join('\n')}

## Significant size changes

Includes any change greater than ${SIGNIFICANCE_THRESHOLD * 100}%:

${
  significantResults.length > 0
    ? `

Expand to show
${header}
${significantResults.join('\n')}

`
    : '(No significant changes)'
}
`);
})();
<commit_msg>fix: prettier ignore removed and fixed (#24811)<commit_after>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

'use strict';

/* eslint-disable no-for-of-loops/no-for-of-loops */

// Hi, if this is your first time editing/reading a Dangerfile, here's a summary:
// It's a JS runtime which helps you provide continuous feedback inside GitHub.
//
// You can see the docs here: http://danger.systems/js/
//
// If you want to test changes Danger, I'd recommend checking out an existing PR
// and then running the `danger pr` command.
//
// You'll need a GitHub token, you can re-use this one:
//
//  0a7d5c3cad9a6dbec2d9 9a5222cf49062a4c1ef7
//
// (Just remove the space)
//
// So, for example:
//
// `DANGER_GITHUB_API_TOKEN=[ENV_ABOVE] yarn danger pr https://github.com/facebook/react/pull/11865

const {markdown, danger, warn} = require('danger');
const {promisify} = require('util');
const glob = promisify(require('glob'));
const gzipSize = require('gzip-size');

const {readFileSync, statSync} = require('fs');

const BASE_DIR = 'base-build';
const HEAD_DIR = 'build';

const CRITICAL_THRESHOLD = 0.02;
const SIGNIFICANCE_THRESHOLD = 0.002;
const CRITICAL_ARTIFACT_PATHS = new Set([
  // We always report changes to these bundles, even if the change is
  // insignificant or non-existent.
  'oss-stable/react-dom/cjs/react-dom.production.min.js',
  'oss-experimental/react-dom/cjs/react-dom.production.min.js',
  'facebook-www/ReactDOM-prod.classic.js',
  'facebook-www/ReactDOM-prod.modern.js',
  'facebook-www/ReactDOMForked-prod.classic.js',
]);

const kilobyteFormatter = new Intl.NumberFormat('en', {
  style: 'unit',
  unit: 'kilobyte',
  minimumFractionDigits: 2,
  maximumFractionDigits: 2,
});

function kbs(bytes) {
  return kilobyteFormatter.format(bytes / 1000);
}

const percentFormatter = new Intl.NumberFormat('en', {
  style: 'percent',
  signDisplay: 'exceptZero',
  minimumFractionDigits: 2,
  maximumFractionDigits: 2,
});

function change(decimal) {
  if (Number === Infinity) {
    return 'New file';
  }
  if (decimal === -1) {
    return 'Deleted';
  }
  if (decimal < 0.0001) {
    return '=';
  }
  return percentFormatter.format(decimal);
}

const header = `
  | Name | +/- | Base | Current | +/- gzip | Base gzip | Current gzip |
  | ---- | --- | ---- | ------- | -------- | --------- | ------------ |`;

function row(result, baseSha, headSha) {
  const diffViewUrl = `https://react-builds.vercel.app/commits/${headSha}/files/${result.path}?compare=${baseSha}`;
  const rowArr = [
    `| [${result.path}](${diffViewUrl})`,
    `**${change(result.change)}**`,
    `${kbs(result.baseSize)}`,
    `${kbs(result.headSize)}`,
    `${change(result.changeGzip)}`,
    `${kbs(result.baseSizeGzip)}`,
    `${kbs(result.headSizeGzip)}`,
  ];
  return rowArr.join(' | ');
}

(async function() {
  // Use git locally to grab the commit which represents the place
  // where the branches differ

  const upstreamRepo = danger.github.pr.base.repo.full_name;
  if (upstreamRepo !== 'facebook/react') {
    // Exit unless we're running in the main repo
    return;
  }

  let headSha;
  let baseSha;
  try {
    headSha = String(readFileSync(HEAD_DIR + '/COMMIT_SHA')).trim();
    baseSha = String(readFileSync(BASE_DIR + '/COMMIT_SHA')).trim();
  } catch {
    warn(
      "Failed to read build artifacts. It's possible a build configuration " +
        'has changed upstream. Try pulling the latest changes from the ' +
        'main branch.'
    );
    return;
  }

  // Disable sizeBot in a Devtools Pull Request. Because that doesn't affect production bundle size.
  const commitFiles = [
    ...danger.git.created_files,
    ...danger.git.deleted_files,
    ...danger.git.modified_files,
  ];
  if (
    commitFiles.every(filename => filename.includes('packages/react-devtools'))
  )
    return;

  const resultsMap = new Map();

  // Find all the head (current) artifacts paths.
  const headArtifactPaths = await glob('**/*.js', {cwd: 'build'});
  for (const artifactPath of headArtifactPaths) {
    try {
      // This will throw if there's no matching base artifact
      const baseSize = statSync(BASE_DIR + '/' + artifactPath).size;
      const baseSizeGzip = gzipSize.fileSync(BASE_DIR + '/' + artifactPath);

      const headSize = statSync(HEAD_DIR + '/' + artifactPath).size;
      const headSizeGzip = gzipSize.fileSync(HEAD_DIR + '/' + artifactPath);
      resultsMap.set(artifactPath, {
        path: artifactPath,
        headSize,
        headSizeGzip,
        baseSize,
        baseSizeGzip,
        change: (headSize - baseSize) / baseSize,
        changeGzip: (headSizeGzip - baseSizeGzip) / baseSizeGzip,
      });
    } catch {
      // There's no matching base artifact. This is a new file.
      const baseSize = 0;
      const baseSizeGzip = 0;
      const headSize = statSync(HEAD_DIR + '/' + artifactPath).size;
      const headSizeGzip = gzipSize.fileSync(HEAD_DIR + '/' + artifactPath);
      resultsMap.set(artifactPath, {
        path: artifactPath,
        headSize,
        headSizeGzip,
        baseSize,
        baseSizeGzip,
        change: Infinity,
        changeGzip: Infinity,
      });
    }
  }

  // Check for base artifacts that were deleted in the head.
  const baseArtifactPaths = await glob('**/*.js', {cwd: 'base-build'});
  for (const artifactPath of baseArtifactPaths) {
    if (!resultsMap.has(artifactPath)) {
      const baseSize = statSync(BASE_DIR + '/' + artifactPath).size;
      const baseSizeGzip = gzipSize.fileSync(BASE_DIR + '/' + artifactPath);
      const headSize = 0;
      const headSizeGzip = 0;
      resultsMap.set(artifactPath, {
        path: artifactPath,
        headSize,
        headSizeGzip,
        baseSize,
        baseSizeGzip,
        change: -1,
        changeGzip: -1,
      });
    }
  }

  const results = Array.from(resultsMap.values());
  results.sort((a, b) => b.change - a.change);

  let criticalResults = [];
  for (const artifactPath of CRITICAL_ARTIFACT_PATHS) {
    const result = resultsMap.get(artifactPath);
    if (result === undefined) {
      throw new Error(
        'Missing expected bundle. If this was an intentional change to the ' +
          'build configuration, update Dangerfile.js accordingly: ' +
          artifactPath
      );
    }
    criticalResults.push(row(result, baseSha, headSha));
  }

  let significantResults = [];
  for (const result of results) {
    // If result exceeds critical threshold, add to top section.
    if (
      (result.change > CRITICAL_THRESHOLD ||
        0 - result.change > CRITICAL_THRESHOLD ||
        // New file
        result.change === Infinity ||
        // Deleted file
        result.change === -1) &&
      // Skip critical artifacts. We added those earlier, in a fixed order.
      !CRITICAL_ARTIFACT_PATHS.has(result.path)
    ) {
      criticalResults.push(row(result, baseSha, headSha));
    }

    // Do the same for results that exceed the significant threshold. These
    // will go into the bottom, collapsed section. Intentionally including
    // critical artifacts in this section, too.
    if (
      result.change > SIGNIFICANCE_THRESHOLD ||
      0 - result.change > SIGNIFICANCE_THRESHOLD ||
      result.change === Infinity ||
      result.change === -1
    ) {
      significantResults.push(row(result, baseSha, headSha));
    }
  }

  markdown(`
Comparing: ${baseSha}...${headSha}

## Critical size changes

Includes critical production bundles, as well as any change greater than ${CRITICAL_THRESHOLD *
    100}%:

${header}
${criticalResults.join('\n')}

## Significant size changes

Includes any change greater than ${SIGNIFICANCE_THRESHOLD * 100}%:

${
  significantResults.length > 0
    ? `

Expand to show
${header}
${significantResults.join('\n')}

`
    : '(No significant changes)'
}
`);
})();
<|endoftext|>


<commit_before>'use strict';
/* Services */
var KMCServices = angular.module('KMC.services', []);

KMCServices.config(['$httpProvider', function($httpProvider) {
    $httpProvider.defaults.useXDomain = true;
    delete $httpProvider.defaults.headers.common['X-Requested-With'];
}]);

KMCServices.factory('playerCache', function($cacheFactory) {
    return $cacheFactory('playerCache', {
        capacity: 10
    });
});

KMCServices.factory('sortSvc', [function() {
    var containers = {};
    var sorter = {};

    var Container = function Container(name) {
        this.name = name;
        this.elements = [];
        containers[name] = this;
    };
    Container.prototype.addElement = function(model) {
        this.elements.push(model);
    };
    Container.prototype.callObjectsUpdate = function() {
        angular.forEach(this.elements, function(model) {
            cl(model.sortVal + ' ' + model.model);
        });
    };
    Container.prototype.removeElement = function(model) {
        var index = this.elements.indexOf(model);
        if (index != -1)
            this.elements.splice(index, 1);
    };
    sorter.sortScope = '';
    sorter.register = function(containerName, model) {
        var container = (typeof  containers[containerName] == 'undefined') ? new Container(containerName) : containers[containerName];
        container.addElement(model);
    };
    sorter.update = function(newVal, oldVal, model) {
        var oldContainer = containers[oldVal];
        var newContainer = (!containers[newVal]) ? new Container(newVal) : containers[newVal];
        if (oldContainer) {
            oldContainer.removeElement(model);
        }
        newContainer.addElement(model);
        if (typeof  sorter.sortScope == 'object') {
            sorter.sortScope.$broadcast('sortContainersChanged');
        }
    };
    sorter.getObjects = function() {
        return containers;
    };
    sorter.saveOrder = function(containersObj) {
        containers = containersObj;
        angular.forEach(containers, function(container) {
            container.callObjectsUpdate();
        });
    };
    return sorter;
}]
);

KMCServices.factory('PlayerService', ['$http', '$modal', '$log', '$q', 'apiService' , '$filter', 'localStorageService',
    function($http, $modal, $log, $q, apiService, $filter, localStorageService) {
        var playersCache = [];
        var currentPlayer = {};
        var previewEntry = '0_ji4qh61l';
        var playersService = {
            'setPreviewEntry': function(id) {
                previewEntry = id;
            },
            'renderPlayer': function() {
                if (currentPlayer && typeof kWidget != "undefined") {
                    var flashvars = ($('html').hasClass('IE8')) ? {'wmode': 'transparent'} : {};
                    kWidget.embed({
                        "targetId": "kVideoTarget", // hard coded for now?
                        "wid": "_" + currentPlayer.partnerId, //$scope.data.partnerId,
                        "uiconf_id": currentPlayer.id,// $scope.data.id,
                        "flashvars": flashvars,
                        "entry_id": previewEntry //$scope.previewEntry
                    });
                }
            },
            playerRefresh: function(option) {
                if (option == 'aspectToggle') {
                    $('#spacer').toggleClass('narrow');
                }
                playersService.renderPlayer(); // for now does nothing different than render,
// but could be used to trigger view changes via notify events rather than complete refresh
            },
            newPlayer: function() {
                var deferred = $q.defer();
                var request = {
                    'service': 'uiConf',
                    'action': 'add',
                    'uiConf:objectType': 'KalturaUiConf',
                    'uiConf:objType': 1,
                    'uiConf:creationMode': 2
                };
                apiService.doRequest(request).then(function(data) {
                    deferred.resolve(data);
                }, function(reason) {
                    deferred.reject(reason); //TODO: how to display the error...
                });
                return deferred.promise;

            },
            clonePlayer: function(srcUi) {
                var deferred = $q.defer();
                var request = {
                    service: 'multirequest',
                    'action': null,
                    '1:service': 'uiconf',
                    '1:action': 'clone',
                    '1:id': srcUi.id,
                    '2:service': 'uiconf',
                    '2:action': 'update',
                    '2:id': '{1:result:id}',
                    '2:uiConf:name': 'Copy of ' + srcUi.name,
                    '2:uiConf:objectType': 'KalturaUiConf'
//'2:uiConf:objType': 1,
// 'uiConf:creationMode': 2
                };
                apiService.doRequest(request).then(function(data) {
                    deferred.resolve(data);
                }, function(reason) {
                    deferred.reject(reason); //TODO: how to display the error...
                });
                return deferred.promise;

            },
            'getPlayer': function(id) {
                var cache = false;
                var deferred = $q.defer();
                if (typeof currentPlayer.id != 'undefined') { // find if player obj is already loaded
                    if (currentPlayer.id == id || id == 'currentEdit') { // this ability to get the player data  we alreayd work on is there for future revert update feature.
                        deferred.resolve(currentPlayer);
                        cache = true;
                    }
                }
                if (!cache) {
// find player data by its ID in the list cache
                    for (var i = 0; i < playersCache.length; i++)
                        if (playersCache[i].id == id) {
                            deferred.resolve(playersCache[i]);
                            currentPlayer = playersCache[i];
                            cache = true;
                        }
                }
                if (!cache) {
                    var request = {
                        'service': 'uiConf',
                        'action': 'get',
                        'id': id

                    };
                    apiService.doRequest(request).then(function(result) {
                            deferred.resolve(result);
                            currentPlayer = result;
                        }
                    );
                }
                return deferred.promise;
            },
            cachePlayers: function(playersList) {
                if ($.isArray(playersList))
                    playersCache = playersCache.concat(playersList);
                else playersCache.push(playersList);
            },
            'deletePlayer': function(id) {
                var deferred = $q.defer();
                var rejectText = $filter('i18n')('Delete action was rejected: ');
                if (typeof id == 'undefined' && currentPlayer)
                    id = currentPlayer.id;
                if (id) {
                    var request = {
                        'service': 'uiConf',
                        'action': 'delete',
                        'id': id

                    };
                    apiService.doRequest(request).then(function(result) {
                            deferred.resolve(result);
                        }, function(msg) {
                            deferred.reject(rejectText + msg);
                        }
                    );
                }
                else {
                    deferred.reject(rejectText);
                }
                return deferred.promise;
            },
            'getRequiredVersion': function() {
                return 2;
            },
            'getPlayers': function() {
                return $http.get('js/services/allplayers.json');
            },
            'playerUpdate': function(playerObj, html5lib) {
// use the upgradePlayer service to convert the old XML config to the new json config object
                var deferred = $q.defer();
                var rejectText = $filter('i18n')('Update player action was rejected: ');
                $http({
                    url: window.kWidget.getPath() + 'services.php',
                    method: "GET",
                    params: {service: 'upgradePlayer', uiconf_id: playerObj.id, ks: localStorageService.get("ks")}
                }).success(function(data, status, headers, config) {
// clean some redundant data from received object
                        if (data['uiConfId']) {
                            delete data['uiConfId'];
                            delete data['widgetId'];
                            delete data.vars['ks'];
                        }
// set an api request to update the uiconf
                        var request = {
                            'service': 'uiConf',
                            'action': 'update',
                            'id': playerObj.id,                   // the id of the player to update
                            'uiConf:tags': 'html5studio,player',  // update tags to prevent breaking the old studio which looks for the tag kdp3
                            'uiConf:html5Url': html5lib,           // update the html5 lib to the new version
                            'uiConf:config': angular.toJson(data)  // update the config object
                        };
                        apiService.doRequest(request).then(function(result) {
                                deferred.resolve(result);
                            }, function(msg) {
                                deferred.reject(rejectText + msg);
                            }
                        );
                    }).error(function(data, status, headers, config) {
                        deferred.reject("Error getting UIConf config: " + data);
                        $log.error('Error getting UIConf config: ' + data);
                    });
                return deferred.promise;
            }
        };
        return playersService;
    }])
;

KMCServices.factory('requestNotificationChannel', ['$rootScope', function($rootScope) {
// private notification messages
    var _START_REQUEST_ = '_START_REQUEST_';
    var _END_REQUEST_ = '_END_REQUEST_';
    var obj = {'customStart': null};
// publish start request notification
    obj.requestStarted = function(customStart) {
        $rootScope.$broadcast(_START_REQUEST_);
        if (customStart) {
            obj.customStart = customStart;
        }
    };
// publish end request notification
    obj.requestEnded = function(customStart) {
        if (obj.customStart) {
            if (customStart == obj.customStart) {
                $rootScope.$broadcast(_END_REQUEST_);
                obj.customStart = null;
            }
            else return;
        }
        else
            $rootScope.$broadcast(_END_REQUEST_);
    };
// subscribe to start request notification
    obj.onRequestStarted = function($scope, handler) {
        $scope.$on(_START_REQUEST_, function(event) {
            handler();
        });
    };
// subscribe to end request notification
    obj.onRequestEnded = function($scope, handler) {
        $scope.$on(_END_REQUEST_, function(event) {
            handler();
        });
    };

    return obj;

}]);

KMCServices.directive('loadingWidget', ['requestNotificationChannel', function(requestNotificationChannel) {
    return {
        restrict: 'EA',
        scope: {},
        replace: true,
        template: '

',
        controller: ['$scope', '$element', function($scope, $element) {
            $scope.spinner = null;
            $scope.spinRunning = false;
            $scope.opts = {
                lines: 15,
                length: 27,
                width: 8,
                radius: 60,
                corners: 1,
                rotate: 0,
                direction: 1,
                color: '#000',
                speed: 0.6,
                trail: 24,
                shadow: true,
                hwaccel: true,
                className: 'spinner',
                zIndex: 2000000000,
                top: 'auto',
                left: 'auto'
            };
            var initSpin = function() {
                $scope.spinner = new Spinner($scope.opts).spin();
            };
            $scope.endSpin = function() {
                if ($scope.spinner)
                    $scope.spinner.stop();
                $scope.spinRunning = false;
            };
            $scope.spin = function() {
                if ($scope.spinRunning)
                    return;
                var target = $element.find('#spinWrapper');
                if ($scope.spinner === null)
                    initSpin();
                $scope.spinner.spin(target[0]);
                $scope.spinRunning = true;
            };
        }],
        link: function(scope, element) {
            element.hide();
            var startRequestHandler = function() {
                element.show();
                scope.spin();
            };
            var endRequestHandler = function() {
                element.hide();
                scope.endSpin();
            };
            requestNotificationChannel.onRequestStarted(scope, startRequestHandler);
            requestNotificationChannel.onRequestEnded(scope, endRequestHandler);
        }
    };
}
])
;

KMCServices.factory('editableProperties', ['$http', function($http) {
    return $http.get('js/services/editableProperties.json');
}]);
KMCServices.service('api', ['$q', function($q) {
    var apiObj = null;
    var deferred = $q.defer();
    //first request - create new kwidget.api
    if (!apiObj) {
        var require = function(file, callback) {
            var head = document.getElementsByTagName("head")[0];
            var script = document.createElement('script');
            script.src = file;
            script.type = 'text/javascript';
            // bind the event to the callback function
            if (script.addEventListener) {
                script.addEventListener("load", callback, false); // IE9+, Chrome, Firefox
            }
            else if (script.readyState) {
                script.onreadystatechange = callback; // IE8
            }
            head.appendChild(script);
        };
        var url = 'http://dev-hudson3.kaltura.dev/html5/html5lib/v2.1/mwEmbedLoader.php?debug=true';
        require(url, function() {
            kWidget.api.prototype.type = 'POST';
            apiObj = new kWidget.api();
            deferred.resolve(apiObj);
        });
    }
    else
        deferred.resolve(apiObj);
    return deferred.promise;
}]);

KMCServices.factory('apiService', ['api', '$q', '$timeout', '$location' , 'localStorageService', 'playerCache', 'requestNotificationChannel', function(api, $q, $timeout, $location, localStorageService, playerCache, requestNotificationChannel) {
    var apiService = {
        apiObj: api,
        unSetks: function() {
            delete this.apiObj;
        },
        setKs: function(ks) {
            this.apiObj.then(function(api) {
                api.setKs(ks);
            });
        },
        setWid: function(wid) {
            this.getClient().then(function(api) {
                api.wid = wid;
            });
        },
        getKey: function(params) {
            var key = '';
            for (var i in params) {
                key += params[i] + '_';
            }
            return key;
        },
        listMedia: function() {
            var request = {
                'service': 'media',
                'action': 'list'

            };
            return this.doRequest(request);
        },
        doRequest: function(params) {
//Creating a deferred object
            var deferred = $q.defer();
            requestNotificationChannel.requestStarted();
            var params_key = this.getKey(params);
            if (playerCache.get(params_key)) {
                deferred.resolve(playerCache.get(params_key));
            } else {
                this.apiObj.then(function(api) {
                    api.doRequest(params, function(data) {
//timeout will trigger another $digest cycle that will trigger the "then" function
                        $timeout(function() {
                            if (data.code) {
                                if (data.code == "INVALID_KS") {
                                    localStorageService.remove('ks');
                                    $location.path("/login");
                                }
                                requestNotificationChannel.requestEnded();
                                deferred.reject(data.code);
                            } else {
                                playerCache.put(params_key, data);
                                requestNotificationChannel.requestEnded();
                                deferred.resolve(data);
                            }
                        }, 0);
                    });
                });
            }
//Returning the promise object
            return deferred.promise;
        }
    };
    return apiService;
}])
;

KMCServices.factory('playerTemplates', ['$http', function($http) {
    return {
        'listSystem': function() {
            return $http.get('http://mrjson.com/data/5263e32d85f7fef869f2a63b/template/list.json');
        },
        'listUser': function() {
            return $http.get('http://mrjson.com/data/5263e32d85f7fef869f2a63b/userTemplates/list.json');
        }
    };

}]);
<commit_msg>updated services and studio.ini<commit_after>'use strict';
/* Services */
var KMCServices = angular.module('KMC.services', []);

KMCServices.config(['$httpProvider', function ($httpProvider) {
    $httpProvider.defaults.useXDomain = true;
    delete $httpProvider.defaults.headers.common['X-Requested-With'];
}]);

KMCServices.factory('playerCache', function ($cacheFactory) {
    return $cacheFactory('playerCache', {
        capacity: 10
    });
});

KMCServices.factory('sortSvc', [function () {
    var containers = {};
    var sorter = {};

    var Container = function Container(name) {
        this.name = name;
        this.elements = [];
        containers[name] = this;
    };
    Container.prototype.addElement = function (model) {
        this.elements.push(model);
    };
    Container.prototype.callObjectsUpdate = function () {
        angular.forEach(this.elements, function (model) {
            cl(model.sortVal + ' ' + model.model);
        });
    };
    Container.prototype.removeElement = function (model) {
        var index = this.elements.indexOf(model);
        if (index != -1)
            this.elements.splice(index, 1);
    };
    sorter.sortScope = '';
    sorter.register = function (containerName, model) {
        var container = (typeof  containers[containerName] == 'undefined') ? new Container(containerName) : containers[containerName];
        container.addElement(model);
    };
    sorter.update = function (newVal, oldVal, model) {
        var oldContainer = containers[oldVal];
        var newContainer = (!containers[newVal]) ? new Container(newVal) : containers[newVal];
        if (oldContainer) {
            oldContainer.removeElement(model);
        }
        newContainer.addElement(model);
        if (typeof  sorter.sortScope == 'object') {
            sorter.sortScope.$broadcast('sortContainersChanged');
        }
    };
    sorter.getObjects = function () {
        return containers;
    };
    sorter.saveOrder = function (containersObj) {
        containers = containersObj;
        angular.forEach(containers, function (container) {
            container.callObjectsUpdate();
        });
    };
    return sorter;
}]
);

KMCServices.factory('PlayerService', ['$http', '$modal', '$log', '$q', 'apiService' , '$filter', 'localStorageService',
    function ($http, $modal, $log, $q, apiService, $filter, localStorageService) {
        var playersCache = [];
        var currentPlayer = {};
        var previewEntry = '0_ji4qh61l';
        var playersService = {
            'setPreviewEntry': function (id) {
                previewEntry = id;
            },
            'renderPlayer': function () {
                if (currentPlayer && typeof kWidget != "undefined") {
                    var flashvars = ($('html').hasClass('IE8')) ? {'wmode': 'transparent'} : {};
                    kWidget.embed({
                        "targetId": "kVideoTarget", // hard coded for now?
                        "wid": "_" + currentPlayer.partnerId, //$scope.data.partnerId,
                        "uiconf_id": currentPlayer.id,// $scope.data.id,
                        "flashvars": flashvars,
                        "entry_id": previewEntry //$scope.previewEntry
                    });
                }
            },
            playerRefresh: function (option) {
                if (option == 'aspectToggle') {
                    $('#spacer').toggleClass('narrow');
                }
                playersService.renderPlayer(); // for now does nothing different than render,
// but could be used to trigger view changes via notify events rather than complete refresh
            },
            newPlayer: function () {
                var deferred = $q.defer();
                var request = {
                    'service': 'uiConf',
                    'action': 'add',
                    'uiConf:objectType': 'KalturaUiConf',
                    'uiConf:objType': 1,
                    'uiConf:creationMode': 2
                };
                apiService.doRequest(request).then(function (data) {
                    deferred.resolve(data);
                }, function (reason) {
                    deferred.reject(reason); //TODO: how to display the error...
                });
                return deferred.promise;

            },
            clonePlayer: function (srcUi) {
                var deferred = $q.defer();
                var request = {
                    service: 'multirequest',
                    'action': null,
                    '1:service': 'uiconf',
                    '1:action': 'clone',
                    '1:id': srcUi.id,
                    '2:service': 'uiconf',
                    '2:action': 'update',
                    '2:id': '{1:result:id}',
                    '2:uiConf:name': 'Copy of ' + srcUi.name,
                    '2:uiConf:objectType': 'KalturaUiConf'
//'2:uiConf:objType': 1,
// 'uiConf:creationMode': 2
                };
                apiService.doRequest(request).then(function (data) {
                    deferred.resolve(data);
                }, function (reason) {
                    deferred.reject(reason); //TODO: how to display the error...
                });
                return deferred.promise;

            },
            'getPlayer': function (id) {
                var cache = false;
                var deferred = $q.defer();
                if (typeof currentPlayer.id != 'undefined') { // find if player obj is already loaded
                    if (currentPlayer.id == id || id == 'currentEdit') { // this ability to get the player data  we alreayd work on is there for future revert update feature.
                        deferred.resolve(currentPlayer);
                        cache = true;
                    }
                }
                if (!cache) {
// find player data by its ID in the list cache
                    for (var i = 0; i < playersCache.length; i++)
                        if (playersCache[i].id == id) {
                            deferred.resolve(playersCache[i]);
                            currentPlayer = playersCache[i];
                            cache = true;
                        }
                }
                if (!cache) {
                    var request = {
                        'service': 'uiConf',
                        'action': 'get',
                        'id': id

                    };
                    apiService.doRequest(request).then(function (result) {
                            deferred.resolve(result);
                            currentPlayer = result;
                        }
                    );
                }
                return deferred.promise;
            },
            cachePlayers: function (playersList) {
                if ($.isArray(playersList))
                    playersCache = playersCache.concat(playersList);
                else playersCache.push(playersList);
            },
            'deletePlayer': function (id) {
                var deferred = $q.defer();
                var rejectText = $filter('i18n')('Delete action was rejected: ');
                if (typeof id == 'undefined' && currentPlayer)
                    id = currentPlayer.id;
                if (id) {
                    var request = {
                        'service': 'uiConf',
                        'action': 'delete',
                        'id': id

                    };
                    apiService.doRequest(request).then(function (result) {
                            deferred.resolve(result);
                        }, function (msg) {
                            deferred.reject(rejectText + msg);
                        }
                    );
                }
                else {
                    deferred.reject(rejectText);
                }
                return deferred.promise;
            },
            'getRequiredVersion': function () {
                return 2;
            },
            'getPlayers': function () {
                return $http.get('js/services/allplayers.json');
            },
            'playerUpdate': function (playerObj, html5lib) {
// use the upgradePlayer service to convert the old XML config to the new json config object
                var deferred = $q.defer();
                var rejectText = $filter('i18n')('Update player action was rejected: ');
                $http({
                    url: window.kWidget.getPath() + 'services.php',
                    method: "GET",
                    params: {service: 'upgradePlayer', uiconf_id: playerObj.id, ks: localStorageService.get("ks")}
                }).success(function (data, status, headers, config) {
// clean some redundant data from received object
                        if (data['uiConfId']) {
                            delete data['uiConfId'];
                            delete data['widgetId'];
                            delete data.vars['ks'];
                        }
// set an api request to update the uiconf
                        var request = {
                            'service': 'uiConf',
                            'action': 'update',
                            'id': playerObj.id,                   // the id of the player to update
                            'uiConf:tags': 'html5studio,player',  // update tags to prevent breaking the old studio which looks for the tag kdp3
                            'uiConf:html5Url': html5lib,           // update the html5 lib to the new version
                            'uiConf:config': angular.toJson(data)  // update the config object
                        };
                        apiService.doRequest(request).then(function (result) {
                                deferred.resolve(result);
                            }, function (msg) {
                                deferred.reject(rejectText + msg);
                            }
                        );
                    }).error(function (data, status, headers, config) {
                        deferred.reject("Error getting UIConf config: " + data);
                        $log.error('Error getting UIConf config: ' + data);
                    });
                return deferred.promise;
            }
        };
        return playersService;
    }])
;

KMCServices.factory('requestNotificationChannel', ['$rootScope', function ($rootScope) {
// private notification messages
    var _START_REQUEST_ = '_START_REQUEST_';
    var _END_REQUEST_ = '_END_REQUEST_';
    var obj = {'customStart': null};
// publish start request notification
    obj.requestStarted = function (customStart) {
        $rootScope.$broadcast(_START_REQUEST_);
        if (customStart) {
            obj.customStart = customStart;
        }
    };
// publish end request notification
    obj.requestEnded = function (customStart) {
        if (obj.customStart) {
            if (customStart == obj.customStart) {
                $rootScope.$broadcast(_END_REQUEST_);
                obj.customStart = null;
            }
            else return;
        }
        else
            $rootScope.$broadcast(_END_REQUEST_);
    };
// subscribe to start request notification
    obj.onRequestStarted = function ($scope, handler) {
        $scope.$on(_START_REQUEST_, function (event) {
            handler();
        });
    };
// subscribe to end request notification
    obj.onRequestEnded = function ($scope, handler) {
        $scope.$on(_END_REQUEST_, function (event) {
            handler();
        });
    };

    return obj;

}]);

KMCServices.directive('loadingWidget', ['requestNotificationChannel', function (requestNotificationChannel) {
    return {
        restrict: 'EA',
        scope: {},
        replace: true,
        template: '

',
        controller: ['$scope', '$element', function ($scope, $element) {
            $scope.spinner = null;
            $scope.spinRunning = false;
            $scope.opts = {
                lines: 15,
                length: 27,
                width: 8,
                radius: 60,
                corners: 1,
                rotate: 0,
                direction: 1,
                color: '#000',
                speed: 0.6,
                trail: 24,
                shadow: true,
                hwaccel: true,
                className: 'spinner',
                zIndex: 2000000000,
                top: 'auto',
                left: 'auto'
            };
            var initSpin = function () {
                $scope.spinner = new Spinner($scope.opts).spin();
            };
            $scope.endSpin = function () {
                if ($scope.spinner)
                    $scope.spinner.stop();
                $scope.spinRunning = false;
            };
            $scope.spin = function () {
                if ($scope.spinRunning)
                    return;
                var target = $element.find('#spinWrapper');
                if ($scope.spinner === null)
                    initSpin();
                $scope.spinner.spin(target[0]);
                $scope.spinRunning = true;
            };
        }],
        link: function (scope, element) {
            element.hide();
            var startRequestHandler = function () {
                element.show();
                scope.spin();
            };
            var endRequestHandler = function () {
                element.hide();
                scope.endSpin();
            };
            requestNotificationChannel.onRequestStarted(scope, startRequestHandler);
            requestNotificationChannel.onRequestEnded(scope, endRequestHandler);
        }
    };
}
])
;

KMCServices.factory('editableProperties', ['$http', function ($http) {
    return $http.get('js/services/editableProperties.json');
}]);

KMCServices.factory('loadINI', ['$http', function ($http) {
    var iniConfig = null;
    return {
        'getINIConfig': function () {
            if (!iniConfig) {
                iniConfig = $http.get('studio.ini', {transformResponse: function (data, headers) {
                    var config = data.substr(data.indexOf('widgets.studio.config = {')+24);
                    data = angular.fromJson(config);
                    return data;
                }});
            }
            return iniConfig;
        }
    };
}]);

KMCServices.provider('api', function () {
    var injector = angular.injector(['ng']);
    var $q = injector.get('$q');

    var apiObj = null;
    return {
        $get: function (loadINI) {
            var deferred = $q.defer();
            //first request - create new kwidget.api
            if (!apiObj) {
                var require = function (file, callback) {
                    var head = document.getElementsByTagName("head")[0];
                    var script = document.createElement('script');
                    script.src = file;
                    script.type = 'text/javascript';
                    // bind the event to the callback function
                    if (script.addEventListener) {
                        script.addEventListener("load", callback, false); // IE9+, Chrome, Firefox
                    }
                    else if (script.readyState) {
                        script.onreadystatechange = callback; // IE8
                    }
                    head.appendChild(script);
                };
                loadINI.getINIConfig().success(function (data) {
                    var url = data.html5lib;
                    var initKw = function () {
                        kWidget.api.prototype.type = 'POST';
                        apiObj = new kWidget.api();
                        deferred.resolve(apiObj);
                    };
                    require(url, function () {
                        if (typeof kWidget == 'undefined') {
                            setTimeout(function () {
                                initKw();
                            }, 100);
                        }
                        else {
                            initKw();
                        }

                    });

                });
            }
            else
                deferred.resolve(apiObj);
            return deferred.promise;
        }
    };
});

KMCServices.factory('apiService', ['api', '$q', '$timeout', '$location' , 'localStorageService', 'playerCache', 'requestNotificationChannel', function (api, $q, $timeout, $location, localStorageService, playerCache, requestNotificationChannel) {
    var apiService = {
        apiObj: api,
        unSetks: function () {
            delete this.apiObj;
        },
        setKs: function (ks) {
            this.apiObj.then(function (api) {
                api.setKs(ks);
            });
        },
        setWid: function (wid) {
            this.getClient().then(function (api) {
                api.wid = wid;
            });
        },
        getKey: function (params) {
            var key = '';
            for (var i in params) {
                key += params[i] + '_';
            }
            return key;
        },
        listMedia: function () {
            var request = {
                'service': 'media',
                'action': 'list'

            };
            return this.doRequest(request);
        },
        doRequest: function (params) {
//Creating a deferred object
            var deferred = $q.defer();
            requestNotificationChannel.requestStarted();
            var params_key = this.getKey(params);
            if (playerCache.get(params_key)) {
                deferred.resolve(playerCache.get(params_key));
            } else {
                this.apiObj.then(function (api) {
                    api.doRequest(params, function (data) {
//timeout will trigger another $digest cycle that will trigger the "then" function
                        $timeout(function () {
                            if (data.code) {
                                if (data.code == "INVALID_KS") {
                                    localStorageService.remove('ks');
                                    $location.path("/login");
                                }
                                requestNotificationChannel.requestEnded();
                                deferred.reject(data.code);
                            } else {
                                playerCache.put(params_key, data);
                                requestNotificationChannel.requestEnded();
                                deferred.resolve(data);
                            }
                        }, 0);
                    });
                });
            }
//Returning the promise object
            return deferred.promise;
        }
    };
    return apiService;
}])
;

KMCServices.factory('playerTemplates', ['$http', function ($http) {
    return {
        'listSystem': function () {
            return $http.get('http://mrjson.com/data/5263e32d85f7fef869f2a63b/template/list.json');
        },
        'listUser': function () {
            return $http.get('http://mrjson.com/data/5263e32d85f7fef869f2a63b/userTemplates/list.json');
        }
    };

}]);
<|endoftext|>


<commit_before>module.exports = {
  // @AJAXとHTTP
  'AJAX送信時': { // @非同期通信(Ajax)でURLにデータを送信し、成功するとcallbackが実行される。その際『対象』にデータが代入される。 // @AJAXそうしんしたとき
    type: 'func',
    josi: [['の'], ['まで', 'へ', 'に']],
    pure: true,
    fn: function (callback, url, sys) {
      let options = sys.__v0['AJAXオプション']
      if (options === '') {options = {method: 'GET'}}
      fetch(url, options).then(res => {
        return res.text()
      }).then(text => {
        sys.__v0['対象'] = text
        callback(text)
      }).catch(err => {
        console.log('[fetch.error]', err)
        sys.__v0['AJAX:ONERROR'](err)
      })
    },
    return_none: true
  },
  'GET送信時': { // @非同期通信(Ajax)でURLにデータを送信し、成功するとcallbackが実行される。その際『対象』にデータが代入される。 // @GETそうしんしたとき
    type: 'func',
    josi: [['の'], ['まで', 'へ', 'に']],
    pure: false,
    fn: function (callback, url, sys) {
      sys.__exec('AJAX送信時', [callback, url, sys])
    },
    return_none: true
  },
  'POSTデータ生成': { // @連想配列をkey=value&key=value...の形式に変換する // @POSTでーたせいせい
    type: 'func',
    josi: [['の', 'を']],
    pure: true,
    fn: function (params, sys) {
      let flist = []
      for (let key in params) {
        const v = params[key]
        const kv = encodeURIComponent(key) + '=' + encodeURIComponent(v)
        flist.push(kv)
      }
      return flist.join('&')
    }
  },
  'POST送信時': { // @AjaxでURLにPARAMSをPOST送信し『対象』にデータを設定 // @POSTそうしんしたとき
    type: 'func',
    josi: [['の'], ['まで', 'へ', 'に'], ['を']],
    pure: false,
    fn: function (callback, url, params, sys) {
      let bodyData = sys.__exec('POSTデータ生成', [params, sys])
      console.log("bodyData=", bodyData)
      const options = {
        method: 'POST',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded'
        },
        body: bodyData
      }
      fetch(url, options).then(res => {
        return res.text()
      }).then(text => {
        sys.__v0['対象'] = text
        callback(text)
      }).catch(err => {
        sys.__v0['AJAX:ONERROR'](err)
      })
    }
  },
  'POSTフォーム送信時': { // @AjaxでURLにPARAMSをフォームとしてPOST送信し『対象』にデータを設定 // @POSTふぉーむそうしんしたとき
    type: 'func',
    josi: [['の'], ['まで', 'へ', 'に'], ['を']],
    pure: true,
    fn: function (callback, url, params, sys) {
      const fd = new FormData()
      for (let key in params)
        {fd.set(key, params[key])}

      let options = {
        method: 'POST',
        body: fd
      }
      fetch(url, options).then(res => {
        return res.text()
      }).then(text => {
        sys.__v0['対象'] = text
        callback(text)
      }).catch(err => {
        sys.__v0['AJAX:ONERROR'](err)
      })
    }
  },
  'AJAX失敗時': { // @Ajax命令でエラーが起きたとき // @AJAXえらーしっぱいしたとき
    type: 'func',
    josi: [['の']],
    pure: true,
    fn: function (callback, sys) {
      sys.__v0['AJAX:ONERROR'] = callback
    }
  },
  'AJAXオプション': {type: 'const', value: ''}, // @AJAXおぷしょん
  'AJAXオプション設定': { // @Ajax命令でオプションを設定 // @AJAXおぷしょんせってい
    type: 'func',
    josi: [['に', 'へ', 'と']],
    pure: true,
    fn: function (option, sys) {
      sys.__v0['AJAXオプション'] = option
    },
    return_none: true
  },
  'AJAX送信': { // @逐次実行構文にて、非同期通信(Ajax)でURLにデータを送信する。成功すると『対象』にデータが代入される。 // @AJAXそうしん
    type: 'func',
    josi: [['まで', 'へ', 'に']],
    pure: true,
    fn: function (url, sys) {
      if (!sys.resolve) {throw new Error('『AJAX送信』は『逐次実行』構文内で利用する必要があります。')}
      sys.__exec('AJAX逐次送信', [url, sys])
    },
    return_none: true
  },
  'AJAX逐次送信': { // @逐次実行構文にて、非同期通信(Ajax)でURLにデータを送信する。成功すると『対象』にデータが代入される。 // @AJAXちくじそうしん
    type: 'func',
    josi: [['まで', 'へ', 'に']],
    pure: true,
    fn: function (url, sys) {
      if (!sys.resolve) {throw new Error('『AJAX逐次送信』は『逐次実行』構文内で利用する必要があります。')}
      sys.resolveCount++
      const resolve = sys.resolve
      const reject = sys.reject
      let options = sys.__v0['AJAXオプション']
      if (options === '') {options = {method: 'GET'}}
      fetch(url, options).then(res => {
        return res.text()
      }).then(text => {
        sys.__v0['対象'] = text
        resolve()
      }).catch(err => {
        reject(err.message)
      })
    },
    return_none: true
  },
  'AJAX保障送信': { // @非同期通信(Ajax)でURLにデータの送信を開始する非同期処理オブジェクト(Promise)を作成する。 // @AJAXほしょうそうしん
    type: 'func',
    josi: [['まで', 'へ', 'に']],
    pure: true,
    fn: function (url, sys) {
      let options = sys.__v0['AJAXオプション']
      if (options === '') {options = {method: 'GET'}}
      return fetch(url, options)
    },
    return_none: false
  },
  'HTTP取得': { // @逐次実行構文にて、非同期通信(Ajax)でURLにデータを送信する。成功すると『対象』にデータが代入される。失敗すると『AJAX失敗時』を実行。 // @HTTPしゅとく
    type: 'func',
    josi: [['の', 'から', 'を']],
    pure: false,
    fn: function (url, sys) {
      if (!sys.resolve) {throw new Error('『HTTP取得』は『逐次実行』構文内で利用する必要があります。')}
      sys.__exec('AJAX逐次送信', [url, sys])
    },
    return_none: true
  },
  'HTTP逐次取得': { // @逐次実行構文にて、非同期通信(Ajax)でURLにデータを送信する。成功すると『対象』にデータが代入される。失敗すると『AJAX失敗時』を実行。 // @HTTPちくじしゅとく
    type: 'func',
    josi: [['の', 'から', 'を']],
    pure: false,
    fn: function (url, sys) {
      if (!sys.resolve) {throw new Error('『HTTP逐次取得』は『逐次実行』構文内で利用する必要があります。')}
      sys.__exec('AJAX逐次送信', [url, sys])
    },
    return_none: true
  },
  'HTTP保障取得': { // @非同期通信(Ajax)でURLにデータの送信を開始する非同期処理オブジェクト(Promise)を作成する。 // @HTTPほしょうしゅとく
    type: 'func',
    josi: [['の', 'から', 'を']],
    pure: true,
    fn: function (url, sys) {
      return sys.__exec('AJAX保障送信', [url, sys])
    },
    return_none: false
  },
  'POST逐次送信': { // @逐次実行構文にて、AjaxでURLにPARAMSをPOST送信し『対象』にデータを設定。失敗すると『AJAX失敗時』を実行。 // @POSTちくじそうしん
    type: 'func',
    josi: [['まで', 'へ', 'に'], ['を']],
    pure: false,
    fn: function (url, params, sys) {
      if (!sys.resolve) {throw new Error('『POST送信』は『逐次実行』構文内で利用する必要があります。')}
      sys.resolveCount++
      const resolve = sys.resolve
      const reject = sys.reject
      let bodyData = sys.__exec('POSTデータ生成', [params, sys])
      const options = {
        method: 'POST',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded'
        },
        body: bodyData
      }
      fetch(url, options).then(res => {
        return res.text()
      }).then(text => {
        sys.__v0['対象'] = text
        resolve(text)
      }).catch(err => {
        reject(err.message)
      })
    },
    return_none: true
  },
  'POST送信': { // @逐次実行構文にて、AjaxでURLにPARAMSをPOST送信し『対象』にデータを設定。失敗すると『AJAX失敗時』を実行。 // @POSTそうしん
    type: 'func',
    josi: [['まで', 'へ', 'に'], ['を']],
    pure: false,
    fn: function (url, params, sys) {
      if (!sys.resolve) {throw new Error('『POST送信』は『逐次実行』構文内で利用する必要があります。')}
      sys.__exec('POST逐次送信', [url, params, sys])
    },
    return_none: true
  },
  'POST保障送信': { // @非同期通信(Ajax)でURLにPARAMSをPOST送信を開始する非同期処理オブジェクト(Promise)を作成する。 // @POSTほしょうそうしん
    type: 'func',
    josi: [['まで', 'へ', 'に'], ['を']],
    pure: true,
    fn: function (url, params, sys) {
      let bodyData = sys.__exec('POSTデータ生成', [params, sys])
      const options = {
        method: 'POST',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded'
        },
        body: bodyData
      }
      return fetch(url, options)
    },
    return_none: false
  },
  'POSTフォーム逐次送信': { // @逐次実行構文にて、AjaxでURLにPARAMSをフォームとしてPOST送信し『対象』にデータを設定。失敗すると『AJAX失敗時』を実行。 // @POSTふぉーむちくじそうしん
    type: 'func',
    josi: [['まで', 'へ', 'に'], ['を']],
    pure: true,
    fn: function (url, params, sys) {
      if (!sys.resolve) {throw new Error('『POSTフォーム逐次送信』は『逐次実行』構文内で利用する必要があります。')}
      sys.resolveCount++
      const resolve = sys.resolve
      const reject = sys.reject
      const fd = new FormData()
      for (let key in params)
        {fd.set(key, params[key])}

      let options = {
        method: 'POST',
        body: fd
      }
      fetch(url, options).then(res => {
        return res.text()
      }).then(text => {
        sys.__v0['対象'] = text
        resolve(text)
      }).catch(err => {
        reject(err.message)
      })
    },
    return_none: true
  },
  'POSTフォーム送信': { // @逐次実行構文にて、AjaxでURLにPARAMSをフォームとしてPOST送信し『対象』にデータを設定。失敗すると『AJAX失敗時』を実行。 // @POSTふぉーむそうしん
    type: 'func',
    josi: [['まで', 'へ', 'に'], ['を']],
    pure: false,
    fn: function (url, params, sys) {
      if (!sys.resolve) {throw new Error('『POSTフォーム送信』は『逐次実行』構文内で利用する必要があります。')}
      sys.__exec('POSTフォーム逐次送信', [url, params, sys])
    },
    return_none: true
  },
  'POSTフォーム保障送信': { // @非同期通信(Ajax)でURLにPARAMSをフォームとしてPOST送信を開始する非同期処理オブジェクト(Promise)を作成する。  // @POSTふぉーむほしょうそうしん
    type: 'func',
    josi: [['まで', 'へ', 'に'], ['を']],
    pure: true,
    fn: function (url, params, sys) {
      const fd = new FormData()
      for (let key in params)
        {fd.set(key, params[key])}

      let options = {
        method: 'POST',
        body: fd
      }
      return fetch(url, options)
    },
    return_none: false
  },
  'AJAX内容取得': { // @非同期通信(Ajax)の応答から内容を指定した形式で取り出すための非同期処理オブジェクト(Promise)を返す。  // @AJAXないようしゅとく
    type: 'func',
    josi: [['から'], ['で']],
    pure: true,
    fn: function (res, type, sys) {
      type = type.toString().toUpperCase()
      if (type === 'TEXT' || type === 'テキスト') {
        return res.text()
      } else
      if (type === 'JSON') {
        return res.json()
      } else
      if (type === 'BLOB') {
        return res.blob()
      } else
      if (type === 'ARRAY' || type === '配列') {
        return res.arrayBuffer()
      } else
      if (type === 'BODY' || type === '本体') {
        return res.body
      }
      return res.body()
    },
    return_none: false
  }
}
<commit_msg>『AJAX送信時』のエイリアス『AJAX受信時』を追加 #1002<commit_after>module.exports = {
  // @AJAXとHTTP
  'AJAX送信時': { // @非同期通信(Ajax)でURLにデータを送信し、成功するとcallbackが実行される。その際『対象』にデータが代入される。『AJAXオプション』を指定できる。 // @AJAXそうしんしたとき
    type: 'func',
    josi: [['の'], ['まで', 'へ', 'に']],
    pure: true,
    fn: function (callback, url, sys) {
      let options = sys.__v0['AJAXオプション']
      if (options === '') {options = {method: 'GET'}}
      fetch(url, options).then(res => {
        return res.text()
      }).then(text => {
        sys.__v0['対象'] = text
        callback(text)
      }).catch(err => {
        console.log('[fetch.error]', err)
        sys.__v0['AJAX:ONERROR'](err)
      })
    },
    return_none: true
  },
  'AJAX受信時': { // @非同期通信(Ajax)を利用してURLからデータを受信した時callbackが実行される。その際『対象』にデータが代入される。『AJAXオプション』を指定できる。 // @AJAXじゅしんしたとき
    type: 'func',
    josi: [['で'], ['から', 'を']],
    pure: true,
    fn: function (callback, url, sys) {
      sys.__exec('AJAX送信時', [callback, url, sys])
    },
    return_none: true
  },
  'GET送信時': { // @非同期通信(Ajax)でURLにデータを送信し、成功するとcallbackが実行される。その際『対象』にデータが代入される。 // @GETそうしんしたとき
    type: 'func',
    josi: [['の'], ['まで', 'へ', 'に']],
    pure: false,
    fn: function (callback, url, sys) {
      sys.__exec('AJAX送信時', [callback, url, sys])
    },
    return_none: true
  },
  'POSTデータ生成': { // @連想配列をkey=value&key=value...の形式に変換する // @POSTでーたせいせい
    type: 'func',
    josi: [['の', 'を']],
    pure: true,
    fn: function (params, sys) {
      let flist = []
      for (let key in params) {
        const v = params[key]
        const kv = encodeURIComponent(key) + '=' + encodeURIComponent(v)
        flist.push(kv)
      }
      return flist.join('&')
    }
  },
  'POST送信時': { // @AjaxでURLにPARAMSをPOST送信し『対象』にデータを設定 // @POSTそうしんしたとき
    type: 'func',
    josi: [['の'], ['まで', 'へ', 'に'], ['を']],
    pure: false,
    fn: function (callback, url, params, sys) {
      let bodyData = sys.__exec('POSTデータ生成', [params, sys])
      const options = {
        method: 'POST',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded'
        },
        body: bodyData
      }
      fetch(url, options).then(res => {
        return res.text()
      }).then(text => {
        sys.__v0['対象'] = text
        callback(text)
      }).catch(err => {
        sys.__v0['AJAX:ONERROR'](err)
      })
    }
  },
  'POSTフォーム送信時': { // @AjaxでURLにPARAMSをフォームとしてPOST送信し『対象』にデータを設定 // @POSTふぉーむそうしんしたとき
    type: 'func',
    josi: [['の'], ['まで', 'へ', 'に'], ['を']],
    pure: true,
    fn: function (callback, url, params, sys) {
      const fd = new FormData()
      for (let key in params)
        {fd.set(key, params[key])}

      let options = {
        method: 'POST',
        body: fd
      }
      fetch(url, options).then(res => {
        return res.text()
      }).then(text => {
        sys.__v0['対象'] = text
        callback(text)
      }).catch(err => {
        sys.__v0['AJAX:ONERROR'](err)
      })
    }
  },
  'AJAX失敗時': { // @Ajax命令でエラーが起きたとき // @AJAXえらーしっぱいしたとき
    type: 'func',
    josi: [['の']],
    pure: true,
    fn: function (callback, sys) {
      sys.__v0['AJAX:ONERROR'] = callback
    }
  },
  'AJAXオプション': {type: 'const', value: ''}, // @AJAXおぷしょん
  'AJAXオプション設定': { // @Ajax命令でオプションを設定 // @AJAXおぷしょんせってい
    type: 'func',
    josi: [['に', 'へ', 'と']],
    pure: true,
    fn: function (option, sys) {
      sys.__v0['AJAXオプション'] = option
    },
    return_none: true
  },
  'AJAX送信': { // @逐次実行構文にて、非同期通信(Ajax)でURLにデータを送信する。成功すると『対象』にデータが代入される。 // @AJAXそうしん
    type: 'func',
    josi: [['まで', 'へ', 'に']],
    pure: true,
    fn: function (url, sys) {
      if (!sys.resolve) {throw new Error('『AJAX送信』は『逐次実行』構文内で利用する必要があります。')}
      sys.__exec('AJAX逐次送信', [url, sys])
    },
    return_none: true
  },
  'AJAX逐次送信': { // @逐次実行構文にて、非同期通信(Ajax)でURLにデータを送信する。成功すると『対象』にデータが代入される。 // @AJAXちくじそうしん
    type: 'func',
    josi: [['まで', 'へ', 'に']],
    pure: true,
    fn: function (url, sys) {
      if (!sys.resolve) {throw new Error('『AJAX逐次送信』は『逐次実行』構文内で利用する必要があります。')}
      sys.resolveCount++
      const resolve = sys.resolve
      const reject = sys.reject
      let options = sys.__v0['AJAXオプション']
      if (options === '') {options = {method: 'GET'}}
      fetch(url, options).then(res => {
        return res.text()
      }).then(text => {
        sys.__v0['対象'] = text
        resolve()
      }).catch(err => {
        reject(err.message)
      })
    },
    return_none: true
  },
  'AJAX保障送信': { // @非同期通信(Ajax)でURLにデータの送信を開始する非同期処理オブジェクト(Promise)を作成する。 // @AJAXほしょうそうしん
    type: 'func',
    josi: [['まで', 'へ', 'に']],
    pure: true,
    fn: function (url, sys) {
      let options = sys.__v0['AJAXオプション']
      if (options === '') {options = {method: 'GET'}}
      return fetch(url, options)
    },
    return_none: false
  },
  'HTTP取得': { // @逐次実行構文にて、非同期通信(Ajax)でURLにデータを送信する。成功すると『対象』にデータが代入される。失敗すると『AJAX失敗時』を実行。 // @HTTPしゅとく
    type: 'func',
    josi: [['の', 'から', 'を']],
    pure: false,
    fn: function (url, sys) {
      if (!sys.resolve) {throw new Error('『HTTP取得』は『逐次実行』構文内で利用する必要があります。')}
      sys.__exec('AJAX逐次送信', [url, sys])
    },
    return_none: true
  },
  'HTTP逐次取得': { // @逐次実行構文にて、非同期通信(Ajax)でURLにデータを送信する。成功すると『対象』にデータが代入される。失敗すると『AJAX失敗時』を実行。 // @HTTPちくじしゅとく
    type: 'func',
    josi: [['の', 'から', 'を']],
    pure: false,
    fn: function (url, sys) {
      if (!sys.resolve) {throw new Error('『HTTP逐次取得』は『逐次実行』構文内で利用する必要があります。')}
      sys.__exec('AJAX逐次送信', [url, sys])
    },
    return_none: true
  },
  'HTTP保障取得': { // @非同期通信(Ajax)でURLにデータの送信を開始する非同期処理オブジェクト(Promise)を作成する。 // @HTTPほしょうしゅとく
    type: 'func',
    josi: [['の', 'から', 'を']],
    pure: true,
    fn: function (url, sys) {
      return sys.__exec('AJAX保障送信', [url, sys])
    },
    return_none: false
  },
  'POST逐次送信': { // @逐次実行構文にて、AjaxでURLにPARAMSをPOST送信し『対象』にデータを設定。失敗すると『AJAX失敗時』を実行。 // @POSTちくじそうしん
    type: 'func',
    josi: [['まで', 'へ', 'に'], ['を']],
    pure: false,
    fn: function (url, params, sys) {
      if (!sys.resolve) {throw new Error('『POST送信』は『逐次実行』構文内で利用する必要があります。')}
      sys.resolveCount++
      const resolve = sys.resolve
      const reject = sys.reject
      let bodyData = sys.__exec('POSTデータ生成', [params, sys])
      const options = {
        method: 'POST',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded'
        },
        body: bodyData
      }
      fetch(url, options).then(res => {
        return res.text()
      }).then(text => {
        sys.__v0['対象'] = text
        resolve(text)
      }).catch(err => {
        reject(err.message)
      })
    },
    return_none: true
  },
  'POST送信': { // @逐次実行構文にて、AjaxでURLにPARAMSをPOST送信し『対象』にデータを設定。失敗すると『AJAX失敗時』を実行。 // @POSTそうしん
    type: 'func',
    josi: [['まで', 'へ', 'に'], ['を']],
    pure: false,
    fn: function (url, params, sys) {
      if (!sys.resolve) {throw new Error('『POST送信』は『逐次実行』構文内で利用する必要があります。')}
      sys.__exec('POST逐次送信', [url, params, sys])
    },
    return_none: true
  },
  'POST保障送信': { // @非同期通信(Ajax)でURLにPARAMSをPOST送信を開始する非同期処理オブジェクト(Promise)を作成する。 // @POSTほしょうそうしん
    type: 'func',
    josi: [['まで', 'へ', 'に'], ['を']],
    pure: true,
    fn: function (url, params, sys) {
      let bodyData = sys.__exec('POSTデータ生成', [params, sys])
      const options = {
        method: 'POST',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded'
        },
        body: bodyData
      }
      return fetch(url, options)
    },
    return_none: false
  },
  'POSTフォーム逐次送信': { // @逐次実行構文にて、AjaxでURLにPARAMSをフォームとしてPOST送信し『対象』にデータを設定。失敗すると『AJAX失敗時』を実行。 // @POSTふぉーむちくじそうしん
    type: 'func',
    josi: [['まで', 'へ', 'に'], ['を']],
    pure: true,
    fn: function (url, params, sys) {
      if (!sys.resolve) {throw new Error('『POSTフォーム逐次送信』は『逐次実行』構文内で利用する必要があります。')}
      sys.resolveCount++
      const resolve = sys.resolve
      const reject = sys.reject
      const fd = new FormData()
      for (let key in params)
        {fd.set(key, params[key])}

      let options = {
        method: 'POST',
        body: fd
      }
      fetch(url, options).then(res => {
        return res.text()
      }).then(text => {
        sys.__v0['対象'] = text
        resolve(text)
      }).catch(err => {
        reject(err.message)
      })
    },
    return_none: true
  },
  'POSTフォーム送信': { // @逐次実行構文にて、AjaxでURLにPARAMSをフォームとしてPOST送信し『対象』にデータを設定。失敗すると『AJAX失敗時』を実行。 // @POSTふぉーむそうしん
    type: 'func',
    josi: [['まで', 'へ', 'に'], ['を']],
    pure: false,
    fn: function (url, params, sys) {
      if (!sys.resolve) {throw new Error('『POSTフォーム送信』は『逐次実行』構文内で利用する必要があります。')}
      sys.__exec('POSTフォーム逐次送信', [url, params, sys])
    },
    return_none: true
  },
  'POSTフォーム保障送信': { // @非同期通信(Ajax)でURLにPARAMSをフォームとしてPOST送信を開始する非同期処理オブジェクト(Promise)を作成する。  // @POSTふぉーむほしょうそうしん
    type: 'func',
    josi: [['まで', 'へ', 'に'], ['を']],
    pure: true,
    fn: function (url, params, sys) {
      const fd = new FormData()
      for (let key in params)
        {fd.set(key, params[key])}

      let options = {
        method: 'POST',
        body: fd
      }
      return fetch(url, options)
    },
    return_none: false
  },
  'AJAX内容取得': { // @非同期通信(Ajax)の応答から内容を指定した形式で取り出すための非同期処理オブジェクト(Promise)を返す。  // @AJAXないようしゅとく
    type: 'func',
    josi: [['から'], ['で']],
    pure: true,
    fn: function (res, type, sys) {
      type = type.toString().toUpperCase()
      if (type === 'TEXT' || type === 'テキスト') {
        return res.text()
      } else
      if (type === 'JSON') {
        return res.json()
      } else
      if (type === 'BLOB') {
        return res.blob()
      } else
      if (type === 'ARRAY' || type === '配列') {
        return res.arrayBuffer()
      } else
      if (type === 'BODY' || type === '本体') {
        return res.body
      }
      return res.body()
    },
    return_none: false
  }
}
<|endoftext|>


<commit_before>import createLWTheme from './createThemeDefaults';
import deepOrange from '@material-ui/core/colors/deepOrange';
import indigo from '@material-ui/core/colors/indigo';

const sansSerifStack = [
  '"freight-sans-pro"',
  'Frutiger',
  '"Frutiger Linotype"',
  'Univers',
  'Calibri',
  '"Gill Sans"',
  '"Gill Sans MT"',
  "Myriad Pro",
  'Myriad',
  '"DejaVu Sans Condensed"',
  '"Liberation Sans"',
  '"Nimbus Sans L"',
  'Tahoma',
  'Geneva',
  '"Helvetica Neue"',
  'Helvetica',
  'Arial',
  'sans-serif'
].join(',')

const palette = {
  primary: indigo,
  secondary: indigo,
  error: {
    main: deepOrange[900]
  },
  background: {
    default: '#fff'
  },
  headerType: "primary"
}

const theme = createLWTheme({
  palette: palette,
  typography: {
    fontFamily: sansSerifStack,
    postStyle: {
      fontFamily: sansSerifStack,
    },
    commentStyle: {
      fontFamily: sansSerifStack
    },
    link: {
      underlinePosition: "72%",
    },
    title: {
      fontWeight: 500,
    },
    display2: {
      fontWeight: 500
    },
    display3: {
      fontWeight: 500
    },
    body1: {
      linkUnderlinePosition: "90%",
    },
  },
  overrides: {
    Header: {
      titleLink: {
        top: 0
      }
    },
    MuiTooltip: {
      tooltip: {
        fontSize: "1rem"
      }
    }
  }
});

export default theme
<commit_msg>lining nums<commit_after>import createLWTheme from './createThemeDefaults';
import deepOrange from '@material-ui/core/colors/deepOrange';
import indigo from '@material-ui/core/colors/indigo';

const sansSerifStack = [
  '"freight-sans-pro"',
  'Frutiger',
  '"Frutiger Linotype"',
  'Univers',
  'Calibri',
  '"Gill Sans"',
  '"Gill Sans MT"',
  "Myriad Pro",
  'Myriad',
  '"DejaVu Sans Condensed"',
  '"Liberation Sans"',
  '"Nimbus Sans L"',
  'Tahoma',
  'Geneva',
  '"Helvetica Neue"',
  'Helvetica',
  'Arial',
  'sans-serif'
].join(',')

const palette = {
  primary: indigo,
  secondary: indigo,
  error: {
    main: deepOrange[900]
  },
  background: {
    default: '#fff'
  },
  headerType: "primary"
}

const theme = createLWTheme({
  palette: palette,
  typography: {
    fontFamily: sansSerifStack,
    postStyle: {
      fontFamily: sansSerifStack,
    },
    commentStyle: {
      fontFamily: sansSerifStack
    },
    link: {
      underlinePosition: "72%",
    },
    title: {
      fontWeight: 500,
    },
    display2: {
      fontWeight: 500
    },
    display3: {
      fontWeight: 500
    },
    body1: {
      linkUnderlinePosition: "90%",
    },
  },
  overrides: {
    Header: {
      titleLink: {
        top: 0
      }
    },
    MuiTooltip: {
      tooltip: {
        fontSize: "1rem"
      }
    },
    PostsVote: {
      voteScores: {
        fontVariantNumeric: "lining-nums",
      }
    }
  }
});

export default theme
<|endoftext|>


<commit_before>'use strict';

import app from 'ampersand-app';
import { applyAsyncLoading } from './loading';
import { findIndex } from 'lodash';

const SET_COMPUTATION = 'SET_COMPUTATION';
const SET_COMPUTATIONS = 'SET_COMPUTATIONS';
const BG_SET_COMPUTATIONS = 'BG_SET_COMPUTATIONS';

const setComputation = (computation) => ({ payload: computation, type: SET_COMPUTATION });
const setComputations = (computations, isBg) => ({
  type: isBg ? BG_SET_COMPUTATIONS : SET_COMPUTATIONS,
  payload: computations,
});

export const fetchComputation = applyAsyncLoading(id => {
  return (dispatch) => {
    return app.core.computations.get(id)
    .then((computation) => {
      dispatch(setComputation(computation));
      return computation;
    })
    .catch((err) => {
      app.notify({
        level: 'error',
        message: 'Failed to fetch computation',
      });
      throw err;
    });
  };
});

export const fetchComputations = applyAsyncLoading(() => {
  return (dispatch) => {
    return app.core.computations.all()
    .then((computations) => {
      dispatch(setComputations(computations));
      return computations;
    })
    .catch((err) => app.notify({
      level: 'error',
      message: `Unable to download computations: ${err}`,
    }));
  };
});

/**
 * efficiently update computation state given a set of computations which may
 * be new or updated.
 * @param {object} opts
 * @param {function} dispatch redux dispatcher
 * @param {object|object[]} toUpdate POJO computations to patch onto existing state
 * @param {boolean} [isBg] indicates that this patch has originated from bg-service (vs. user)
 * @returns {undefined}
 */
export const updateComputations = ({ toUpdate, isBg }) =>
  (dispatch, getState) => {
    const currComps = getState().computationsDuck.computations;
    if (!Array.isArray(toUpdate)) {
      toUpdate = [toUpdate];
    }
    toUpdate.forEach((changed) => {
      const toSwapNdx = findIndex(currComps, { _id: changed._id });
      if (toSwapNdx >= 0) {
        currComps[toSwapNdx] = changed;
      } else {
        currComps.push(changed);
      }
    });
    dispatch(setComputations(currComps, isBg));
  };

const INITIAL_STATE = {
  computation: null,
  computations: [],
};

export default function reducer(state = INITIAL_STATE, action) {
  switch (action.type) {
    case BG_SET_COMPUTATIONS:
    case SET_COMPUTATION:
      return { ...state, computation: action.payload };
    case SET_COMPUTATIONS:
      return { ...state, computations: [...action.payload] };
    default:
      return state;
  }
}
<commit_msg>consistent exports and comments<commit_after>'use strict';

import app from 'ampersand-app';
import { applyAsyncLoading } from './loading';
import { findIndex } from 'lodash';

// Actions
export const SET_COMPUTATION = 'SET_COMPUTATION';
export const SET_COMPUTATIONS = 'SET_COMPUTATIONS';
export const BG_SET_COMPUTATIONS = 'BG_SET_COMPUTATIONS';

// Action Creators
export const setComputation = (computation) => ({ payload: computation, type: SET_COMPUTATION });
export const setComputations = (computations, isBg) => ({
  type: isBg ? BG_SET_COMPUTATIONS : SET_COMPUTATIONS,
  payload: computations,
});

// Helpers
export const fetchComputation = applyAsyncLoading(id => {
  return (dispatch) => {
    return app.core.computations.get(id)
    .then((computation) => {
      dispatch(setComputation(computation));
      return computation;
    })
    .catch((err) => {
      app.notify({
        level: 'error',
        message: 'Failed to fetch computation',
      });
      throw err;
    });
  };
});

export const fetchComputations = applyAsyncLoading(() => {
  return (dispatch) => {
    return app.core.computations.all()
    .then((computations) => {
      dispatch(setComputations(computations));
      return computations;
    })
    .catch((err) => app.notify({
      level: 'error',
      message: `Unable to download computations: ${err}`,
    }));
  };
});

/**
 * efficiently update computation state given a set of computations which may
 * be new or updated.
 * @param {object} opts
 * @param {function} dispatch redux dispatcher
 * @param {object|object[]} toUpdate POJO computations to patch onto existing state
 * @param {boolean} [isBg] indicates that this patch has originated from bg-service (vs. user)
 * @returns {undefined}
 */
export const updateComputations = ({ toUpdate, isBg }) =>
  (dispatch, getState) => {
    const currComps = getState().computationsDuck.computations;
    if (!Array.isArray(toUpdate)) {
      toUpdate = [toUpdate];
    }
    toUpdate.forEach((changed) => {
      const toSwapNdx = findIndex(currComps, { _id: changed._id });
      if (toSwapNdx >= 0) {
        currComps[toSwapNdx] = changed;
      } else {
        currComps.push(changed);
      }
    });
    dispatch(setComputations(currComps, isBg));
  };

const INITIAL_STATE = {
  computation: null,
  computations: [],
};

// Reducer
export default function reducer(state = INITIAL_STATE, action) {
  switch (action.type) {
    case BG_SET_COMPUTATIONS:
    case SET_COMPUTATION:
      return { ...state, computation: action.payload };
    case SET_COMPUTATIONS:
      return { ...state, computations: [...action.payload] };
    default:
      return state;
  }
}
<|endoftext|>