<commit_before>import {
    spawn
} from 'child_process'
import {
    commands
} from '../../utils/config'
import {
    command,
    showMessage
} from '../../utils/helpers'
import sudo from 'sudo-prompt'
import fs from 'fs'
import SidebarItem from './SidebarItem'
import TableTitle from './TableTitle'
import TableItems from './TableItems'

export default {
    template: `

                        <sidebar-item text="Apt Cache" :length="aptCachesList.length">
						    <input type="checkbox" v-model:checked="aptCacheSelect">
                        </sidebar-item>

                        <sidebar-item text="Crash Reports" :length="crashReportsList.length">
						    <input type="checkbox" v-model:checked="crashReportsSelect">
                        </sidebar-item>

                        <sidebar-item text="System Logs" :length="systemLogsList.length">
						    <input type="checkbox" v-model:checked="systemLogsSelect">
                        </sidebar-item>

                        <sidebar-item text="App Cache" :length="appCachesList.length">
						    <input type="checkbox" v-model:checked="appCacheSelect">
                        </sidebar-item>

                        <sidebar-item text="Trash" :length="trashSize">
						    <input type="checkbox" v-model:checked="trashSelect">
                        </sidebar-item>

					<input type="button" id="system-scan-btn" @click="systemScan" value="System Scan" />

                            <input type="checkbox" @change="checkAllAptCaches">

                            <input type="checkbox" :value="item" v-model="checkedAptCaches">

                            <input type="checkbox" @change="checkAllCrashReports">

                            <input type="checkbox" :value="item" v-model="checkedCrashReports">

                            <input type="checkbox" @change="checkAllSystemLogs">

                            <input type="checkbox" :value="item" v-model="checkedSystemLogs">

                            <input type="checkbox" @change="checkAllAppCaches">

                            <input type="checkbox" :value="item" v-model="checkedAppCaches">

				<input type="button" id="clean-btn" @click="systemClean" value="Clean" />

`,

    components: {
        'sidebar-item': SidebarItem,
        'table-title': TableTitle,
        'table-items': TableItems
    },
    data() {
        return {
            aptCacheSelect: false,
            crashReportsSelect: false,
            systemLogsSelect: false,
            appCacheSelect: false,
            trashSelect: false,

            aptCachesList: [],
            crashReportsList: [],
            systemLogsList: [],
            appCachesList: [],

            checkedAptCaches: [],
            checkedCrashReports: [],
            checkedSystemLogs: [],
            checkedAppCaches: [],

            trashSize: 0
        }
    },
    methods: {
        systemScan() {
            // Lists cleaning
            this.aptCachesList = []
            this.crashReportsList = []
            this.systemLogsList = []
            this.appCachesList = []

            if (this.aptCacheSelect) {
                fs.readdir(commands.aptCachePath, 'utf8', (err, files) => {
                    if (!err)
                        files.filter(file => file.endsWith('.deb'))
                        .forEach(file => this.aptCachesList.push(file))
                    else
                        console.log(err)
                })
            } else {
                this.checkedAptCaches = []
            }

            if (this.crashReportsSelect) {
                fs.readdir(commands.crashReportsPath, 'utf8', (err, files) => {
                    if (!err)
                        files.forEach(file => this.crashReportsList.push(file))
                    else
                        console.log(err)
                })
            } else {
                this.checkedCrashReports = []
            }

            if (this.systemLogsSelect) {
                fs.readdir(commands.systemLogsPath, 'utf8', (err, files) => {
                    if (!err)
                        files.forEach(file => this.systemLogsList.push(file))
                    else
                        console.log(err)
                })
            } else {
                this.checkedSystemLogs = []
            }

            if (this.appCacheSelect) {
                fs.readdir(commands.appCachePath, 'utf8', (err, files) => {
                    if (!err)
                        files.forEach(file => this.appCachesList.push(file))
                    else
                        console.log(err)
                })
            } else {
                this.checkedAppCaches = []
            }
        },
        // System clean
        systemClean() {
            let filesToRemove = ''

            if (this.checkedAptCaches) {
                this.checkedAptCaches.forEach(file => {
                    filesToRemove += `rm -rf ${commands.aptCachePath}${file}; `
                })
            }

            if (this.checkedCrashReports) {
                this.checkedCrashReports.forEach(file => {
                    filesToRemove += `rm -rf ${commands.crashReportsPath}${file}; `
                })
            }

            if (this.checkedSystemLogs) {
                this.checkedSystemLogs.forEach(file => {
                    filesToRemove += `rm -rf ${commands.systemLogsPath}${file}; `
                })
            }

            if (this.checkedAppCaches) {
                this.checkedAppCaches.forEach(file => {
                    filesToRemove += `rm -rf ${commands.appCachePath}${file}; `
                })
            }

            if (filesToRemove) {
                sudo.exec(command(filesToRemove), {
                        name: 'Stacer'
                    },
                    (error, stdout, stderr) => {
                        if (stderr)
                            showMessage(`System cleaning failed.`, 'error')
                        else {
                            this.aptCachesList = this.aptCachesList.filter(item => this.checkedAptCaches.indexOf(item) == -1)
                            this.crashReportsList = this.crashReportsList.filter(item => this.checkedCrashReports.indexOf(item) == -1)
                            this.systemLogsList = this.systemLogsList.filter(item => this.checkedSystemLogs.indexOf(item) == -1)
                            this.appCachesList = this.appCachesList.filter(item => this.checkedAppCaches.indexOf(item) == -1)

                            this.checkedAptCaches = []
                            this.checkedCrashReports = []
                            this.checkedSystemLogs = []
                            this.checkedAppCaches = []

                            showMessage(`System cleaned.`, 'success')
                        }
                    })
            }
        },
        // Check all items
        checkAllAptCaches(e) {
            this.checkedAptCaches = []
            if (e.target.checked)
                this.checkedAptCaches.push(...this.aptCachesList)
        },
        checkAllCrashReports(e) {
            this.checkedCrashReports = []
            if (e.target.checked)
                this.checkedCrashReports.push(...this.crashReportsList)
        },
        checkAllSystemLogs(e) {
            this.checkedSystemLogs = []
            if (e.target.checked)
                this.checkedSystemLogs.push(...this.systemLogsList)
        },
        checkAllAppCaches(e) {
            this.checkedAppCaches = []
            if (e.target.checked)
                this.checkedAppCaches.push(...this.appCachesList)
        }
    },
    watch: {
        appCacheSelect: checked => {
            if (checked)
                showMessage('Deleting applications\' caches can cause problems. Please be careful.', 'warning')
        }
    }
}<commit_msg>added trash to system cleaner<commit_after>import {
    spawn
} from 'child_process'
import {
    commands
} from '../../utils/config'
import {
    command,
    showMessage
} from '../../utils/helpers'
import fs from 'fs'
import sudo from 'sudo-prompt'
// Components
import SidebarItem from './SidebarItem'
import TableTitle from './TableTitle'
import TableItems from './TableItems'

export default {
    template: `

                        <sidebar-item text="Apt Cache" :length="aptCachesList.length">
						    <input type="checkbox" v-model:checked="aptCacheSelect">
                        </sidebar-item>

                        <sidebar-item text="Crash Reports" :length="crashReportsList.length">
						    <input type="checkbox" v-model:checked="crashReportsSelect">
                        </sidebar-item>

                        <sidebar-item text="System Logs" :length="systemLogsList.length">
						    <input type="checkbox" v-model:checked="systemLogsSelect">
                        </sidebar-item>

                        <sidebar-item text="App Cache" :length="appCachesList.length">
						    <input type="checkbox" v-model:checked="appCacheSelect">
                        </sidebar-item>

                        <sidebar-item text="Trash" :length="trashSize">
						    <input type="checkbox" v-model:checked="trashSelect">
                        </sidebar-item>

					<input type="button" id="system-scan-btn" @click="systemScan" value="System Scan" />

                            <input type="checkbox" @change="checkAllAptCaches">

                            <input type="checkbox" :value="item" v-model="checkedAptCaches">

                            <input type="checkbox" @change="checkAllCrashReports">

                            <input type="checkbox" :value="item" v-model="checkedCrashReports">

                            <input type="checkbox" @change="checkAllSystemLogs">

                            <input type="checkbox" :value="item" v-model="checkedSystemLogs">

                            <input type="checkbox" @change="checkAllAppCaches">

                            <input type="checkbox" :value="item" v-model="checkedAppCaches">

				<input type="button" id="clean-btn" @click="systemClean" value="Clean" />

`,

    components: {
        'sidebar-item': SidebarItem,
        'table-title': TableTitle,
        'table-items': TableItems
    },
    data() {
        return {
            aptCacheSelect: false,
            crashReportsSelect: false,
            systemLogsSelect: false,
            appCacheSelect: false,
            trashSelect: false,

            aptCachesList: [],
            crashReportsList: [],
            systemLogsList: [],
            appCachesList: [],

            checkedAptCaches: [],
            checkedCrashReports: [],
            checkedSystemLogs: [],
            checkedAppCaches: [],

            trashSize: 0
        }
    },
    methods: {
        systemScan() {
            // Lists cleaning
            this.aptCachesList = []
            this.crashReportsList = []
            this.systemLogsList = []
            this.appCachesList = []
            this.trashSize = 0

            if (this.aptCacheSelect) {
                fs.readdir(commands.aptCachePath, 'utf8', (err, files) => {
                    if (!err)
                        files.filter(file => file.endsWith('.deb'))
                        .forEach(file => this.aptCachesList.push(file))
                    else
                        console.log(err)
                })
            } else {
                this.checkedAptCaches = []
            }

            if (this.crashReportsSelect) {
                fs.readdir(commands.crashReportsPath, 'utf8', (err, files) => {
                    if (!err)
                        files.forEach(file => this.crashReportsList.push(file))
                    else
                        console.log(err)
                })
            } else {
                this.checkedCrashReports = []
            }

            if (this.systemLogsSelect) {
                fs.readdir(commands.systemLogsPath, 'utf8', (err, files) => {
                    if (!err)
                        files.forEach(file => this.systemLogsList.push(file))
                    else
                        console.log(err)
                })
            } else {
                this.checkedSystemLogs = []
            }

            if (this.appCacheSelect) {
                fs.readdir(commands.appCachePath, 'utf8', (err, files) => {
                    if (!err)
                        files.forEach(file => this.appCachesList.push(file))
                    else
                        console.log(err)
                })
            } else {
                this.checkedAppCaches = []
            }

            if (this.trashSelect) {
                function formatBytes(bytes, decimals) {
                    if (bytes == 0) return '0 Bytes'
                    var k = 1000,
                        dm = decimals + 1 || 3,
                        sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
                        i = Math.floor(Math.log(bytes) / Math.log(k))
                    return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]
                }

                function getSize(path = '') {
                    path += '/'
                    let totalSize = 0
                    try {
                        let trashFiles = fs.readdirSync('/home/oguzhan/.local/share/Trash/files' + path)
                        trashFiles.forEach(fileName => {

                            let stats = fs.statSync('/home/oguzhan/.local/share/Trash/files' + path + fileName)
                            if (!stats.isDirectory())
                                totalSize += stats.size
                            else
                                totalSize += getSize(path + fileName)
                        })
                    } catch (error) {
                        console.log(error)
                    }
                    return totalSize
                }
                this.trashSize = formatBytes(getSize(), 0)
            }
        },
        // System clean
        systemClean() {
            let filesToRemove = ''

            if (this.checkedAptCaches) {
                this.checkedAptCaches.forEach(file => {
                    filesToRemove += `rm -rf ${commands.aptCachePath}${file}; `
                })
            }

            if (this.checkedCrashReports) {
                this.checkedCrashReports.forEach(file => {
                    filesToRemove += `rm -rf ${commands.crashReportsPath}${file}; `
                })
            }

            if (this.checkedSystemLogs) {
                this.checkedSystemLogs.forEach(file => {
                    filesToRemove += `rm -rf ${commands.systemLogsPath}${file}; `
                })
            }

            if (this.checkedAppCaches) {
                this.checkedAppCaches.forEach(file => {
                    filesToRemove += `rm -rf ${commands.appCachePath}${file}; `
                })
            }

            if (filesToRemove) {
                sudo.exec(command(filesToRemove), {
                        name: 'Stacer'
                    },
                    (error, stdout, stderr) => {
                        if (stderr)
                            showMessage(`System cleaning failed.`, 'error')
                        else {
                            this.aptCachesList = this.aptCachesList.filter(item => this.checkedAptCaches.indexOf(item) == -1)
                            this.crashReportsList = this.crashReportsList.filter(item => this.checkedCrashReports.indexOf(item) == -1)
                            this.systemLogsList = this.systemLogsList.filter(item => this.checkedSystemLogs.indexOf(item) == -1)
                            this.appCachesList = this.appCachesList.filter(item => this.checkedAppCaches.indexOf(item) == -1)

                            this.checkedAptCaches = []
                            this.checkedCrashReports = []
                            this.checkedSystemLogs = []
                            this.checkedAppCaches = []

                            showMessage(`System cleaned.`, 'success')
                        }
                    })
            }
        },
        // Check all items
        checkAllAptCaches(e) {
            this.checkedAptCaches = []
            if (e.target.checked)
                this.checkedAptCaches.push(...this.aptCachesList)
        },
        checkAllCrashReports(e) {
            this.checkedCrashReports = []
            if (e.target.checked)
                this.checkedCrashReports.push(...this.crashReportsList)
        },
        checkAllSystemLogs(e) {
            this.checkedSystemLogs = []
            if (e.target.checked)
                this.checkedSystemLogs.push(...this.systemLogsList)
        },
        checkAllAppCaches(e) {
            this.checkedAppCaches = []
            if (e.target.checked)
                this.checkedAppCaches.push(...this.appCachesList)
        }
    },
    watch: {
        appCacheSelect: checked => {
            if (checked)
                showMessage('Deleting applications\' caches can cause problems. Please be careful.', 'warning')
        }
    }
}<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015, Groupon, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * Neither the name of GROUPON nor the names of its contributors may be
 * used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

'use strict';

const assert = require('assert');
const flatMap = require('array.prototype.flatmap');

const lighthouse = require('lighthouse');

/**
 * @typedef {import('lighthouse/types/lhr')} LH
 * @typedef {import('lighthouse/types/config').LH.Config} LH_Config
 * @typedef {import('lighthouse/types/externs').SharedFlagsSettings} LH_Flags
 * @typedef {import('lighthouse/types/artifacts').Artifacts} LH_Artifacts
 *
 * @typedef {Object} parsedLHResults
 * @property {number} score
 * @property {LH.Result.audits} audits
 * @property {function(string?): Record<string, any>|Record<string, any>[]} error
 * @property {function(): string} errorString
 * @property {function(number): boolean} isSuccess
 * @property {function(string?): Record<string, auditInfo>|Record<string, auditInfo>[]} success
 */

const defaultConfig = {
  extends: 'lighthouse:default',
  settings: {
    onlyCategories: [],
    throttlingMethod: 'simulate',
  },
};

const defaultFlags = {
  chromeFlags: [
    '--disable-gpu',
    '--headless',
    '--disable-storage-reset',
    '--enable-logging',
    '--disable-device-emulation',
    '--no-sandbox',
  ],
};

/**
 * @param {string} type
 * @param {Array<string>} [skipAudits]
 * @returns {Object}
 */
function getConfigByType(type, skipAudits) {
  const config = JSON.parse(JSON.stringify(defaultConfig));
  if (type) {
    config.settings.onlyCategories.push(type);
    if (Array.isArray(skipAudits) && skipAudits.length) {
      config.settings = { ...config.settings, skipAudits };
    }
  }
  return config;
}

/**
 *
 * @param {Record<string, any>} success
 * @param {Record<string, any>} failure
 * @returns {number}
 */
function getTotalScore(success, failure) {
  const successCount = Object.keys(success).length;
  const errorCount = Object.keys(failure).length;

  if (successCount + errorCount === 0) {
    return 0;
  }
  return (successCount * 100) / (successCount + errorCount);
}

/**
 *
 * @param {LH.RunnerResult} results
 * @returns {parsedLHResults}
 */
function parseLhResult(results) {
  if (!results || !results.lhr || !results.lhr.audits) {
    throw new Error(`Error fetching lighthouse audit results`);
  }

  const { audits } = results.lhr;
  const errorsObj = {};
  const notApplicableObj = {};
  const successObj = {};

  /**
   *
   * @typedef {{description: LH.Audit.Result.description, details: LH.Audit.Result.details}} auditInfo
   */

  Object.values(audits).forEach(audit => {
    const { id, description, details, score, scoreDisplayMode } = audit;

    /**
     *
     * @type {auditInfo}
     */
    const auditInfo = { description, details };
    let snippets;

    if (score) {
      successObj[id] = auditInfo;
    } else if (scoreDisplayMode === 'notApplicable') {
      notApplicableObj[id] = auditInfo;
    } else if (scoreDisplayMode !== 'manual') {
      snippets = [];
      ((details && details.items) || []).forEach(item =>
        snippets.push((item.node && item.node.snippet) || '')
      );
    }

    errorsObj[id] = { description, snippets };
  });

  const score = getTotalScore(successObj, errorsObj);

  return {
    audits,
    score,
    /**
     * @param {number} cutoff
     */
    isSuccess(cutoff) {
      assert.ok(
        score >= cutoff,
        `Score ${score} is smaller than expected cutoff score ${cutoff}`
      );
    },
    /**
     * @param {string?} audit
     * @returns {Record<string, auditInfo>}
     */
    success(audit) {
      return audit ? successObj[audit] : successObj;
    },
    /**
     * @param {string?} audit
     * @returns {Record<string, any>}
     */
    errors(audit) {
      return audit ? errorsObj[audit] : errorsObj;
    },
    /**
     * @returns {string}
     */
    errorString() {
      const errorList = [];

      for (const id in errorsObj) {
        const description = errorsObj[id].description;
        const snippets = errorsObj[id].snippets;
        errorList.push(`${description}:\n\t${snippets.join('\n\t')}`);
      }

      return errorList.join('\n\n');
    },
  };
}

/**
 *
 * @param {string} category
 * @param {number} minScore
 * @param {Array<string>} [skipAudits]
 * @returns {Promise<parsedLHResults>}
 */
async function assertScoreByCategory(category, minScore, skipAudits = []) {
  minScore = minScore || 100;

  category = category.toLowerCase();

  const config = getConfigByType(category, skipAudits);

  const results = await this.getLighthouseData(defaultFlags, config).then(
    parseLhResult
  );

  assert.ok(
    results.score >= minScore,
    `${category} score ${results.score} to be greater than ${minScore}`
  );

  return results;
}

/**
 *
 * @param {number} minScore
 * @param {Array<string>} [skipAudits]
 * @returns {Promise<parsedLHResults>}
 */
function assertPerformanceScore(minScore, skipAudits = []) {
  return this.assertScoreByCategory('performance', minScore, [
    ...skipAudits,
    'final-screenshot',
    'is-on-https',
    'screenshot-thumbnails',
  ]);
}

/**
 *
 * @param {number} minScore
 * @param {Array<string>} [skipAudits]
 * @returns {Promise<parsedLHResults>}
 */
function assertAccessibilityScore(minScore, skipAudits = []) {
  return this.assertScoreByCategory('accessibility', minScore, skipAudits);
}

/**
 *
 * @param {number} minScore
 * @param {Array<string>} skipAudits
 * @returns {Promise<parsedLHResults>}
 */
function assertBestPracticesScore(minScore, skipAudits = []) {
  return this.assertScoreByCategory('best-practices', minScore, skipAudits);
}

/**
 *
 * @param {number} minScore
 * @param {Array<string>} [skipAudits]
 * @returns {Promise<parsedLHResults>}
 */
function assertSeoScore(minScore, skipAudits = []) {
  return this.assertScoreByCategory('seo', minScore, skipAudits);
}

/**
 *
 * @param {number} minScore
 * @param {Array<string>} [skipAudits]
 * @returns {Promise<parsedLHResults>}
 */
function assertPwaScore(minScore, skipAudits = []) {
  return this.assertScoreByCategory('pwa', minScore, skipAudits);
}

/**
 *
 * @param {LH_Flags.Flags?} flags
 * @param {LH_Config.Json?} lhConfig
 * @returns {Promise<parsedLHResults>}
 * @legacy
 */
function runLighthouseAudit(flags, lhConfig) {
  return this.getLighthouseData(flags, lhConfig).then(parseLhResult);
}

/**
 * @param {{flags?: LH_Flags.Flags, config?: LH_Config.Json, ignore?:boolean}} options
 * @returns {Promise<{Object[]|[]>}
 */
async function a11yAudit(options = {}) {
  const { flags, config, ignore } = options;

  let violationsFilter; // function to filter violations
  if (typeof ignore === 'function') {
    violationsFilter = violation => !ignore(violation);
  } else if (Array.isArray(ignore)) {
    // e.g. ignore: ['html-has-lang']
    violationsFilter = violation => !ignore.includes(violation.id);
  } else {
    violationsFilter = () => true;
  }

  const result = await this.getLighthouseData(
    flags || defaultFlags,
    config || getConfigByType('accessibility')
  );

  // TODO: with node 12 use Array.prototype.flatMap
  return flatMap(
    result.artifacts.Accessibility.violations.filter(violationsFilter),
    violation => {
      const { nodes, ...violationData } = violation;
      return nodes.map(node => {
        return {
          ...violationData,
          auditId: violationData.id,
          selector: Array.isArray(node.target) ? node.target.join(' ') : '',
          path: node.path,
          snippet: node.snippet,
        };
      });
    }
  );
}

/**
 * @param {LH_Flags.Flags?} flags
 * @param {LH_Config.Json?} config
 * @returns {Promise<LH.RunnerResult>}
 */
async function getLighthouseData(flags, config) {
  if (!lighthouse) {
    throw new Error('Lighthouse requires a newer version of node');
  }
  const devtoolsPort = await this.getChromeDevtoolsPort();
  const options = { port: devtoolsPort, ...flags };
  const url = await this.url();

  return lighthouse(url, options, config);
}

module.exports = {
  a11yAudit,
  assertAccessibilityScore,
  assertBestPracticesScore,
  assertPerformanceScore,
  assertPwaScore,
  assertSeoScore,
  assertScoreByCategory,
  getLighthouseData,
  runLighthouseAudit,
};
<commit_msg>fix: linter tweak<commit_after>/*
 * Copyright (c) 2015, Groupon, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * Neither the name of GROUPON nor the names of its contributors may be
 * used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

'use strict';

const assert = require('assert');
const flatMap = require('array.prototype.flatmap');

const lighthouse = require('lighthouse');

/**
 * @typedef {import('lighthouse/types/lhr')} LH
 * @typedef {import('lighthouse/types/config').LH.Config} LH_Config
 * @typedef {import('lighthouse/types/externs').SharedFlagsSettings} LH_Flags
 * @typedef {import('lighthouse/types/artifacts').Artifacts} LH_Artifacts
 *
 * @typedef {Object} parsedLHResults
 * @property {number} score
 * @property {LH.Result.audits} audits
 * @property {function(string?): Record<string, any>|Record<string, any>[]} error
 * @property {function(): string} errorString
 * @property {function(number): boolean} isSuccess
 * @property {function(string?): Record<string, auditInfo>|Record<string, auditInfo>[]} success
 */

const defaultConfig = {
  extends: 'lighthouse:default',
  settings: {
    onlyCategories: [],
    throttlingMethod: 'simulate',
  },
};

const defaultFlags = {
  chromeFlags: [
    '--disable-gpu',
    '--headless',
    '--disable-storage-reset',
    '--enable-logging',
    '--disable-device-emulation',
    '--no-sandbox',
  ],
};

/**
 * @param {string} type
 * @param {Array<string>} [skipAudits]
 * @returns {Object}
 */
function getConfigByType(type, skipAudits) {
  const config = JSON.parse(JSON.stringify(defaultConfig));
  if (type) {
    config.settings.onlyCategories.push(type);
    if (Array.isArray(skipAudits) && skipAudits.length) {
      config.settings = { ...config.settings, skipAudits };
    }
  }
  return config;
}

/**
 *
 * @param {Record<string, any>} success
 * @param {Record<string, any>} failure
 * @returns {number}
 */
function getTotalScore(success, failure) {
  const successCount = Object.keys(success).length;
  const errorCount = Object.keys(failure).length;

  if (successCount + errorCount === 0) {
    return 0;
  }
  return (successCount * 100) / (successCount + errorCount);
}

/**
 *
 * @param {LH.RunnerResult} results
 * @returns {parsedLHResults}
 */
function parseLhResult(results) {
  if (!results || !results.lhr || !results.lhr.audits) {
    throw new Error(`Error fetching lighthouse audit results`);
  }

  const { audits } = results.lhr;
  const errorsObj = {};
  const notApplicableObj = {};
  const successObj = {};

  /**
   *
   * @typedef {{description: LH.Audit.Result.description, details: LH.Audit.Result.details}} auditInfo
   */

  Object.values(audits).forEach(audit => {
    const { id, description, details, score, scoreDisplayMode } = audit;

    /**
     *
     * @type {auditInfo}
     */
    const auditInfo = { description, details };
    const snippets = [];

    if (score) {
      successObj[id] = auditInfo;
    } else if (scoreDisplayMode === 'notApplicable') {
      notApplicableObj[id] = auditInfo;
    } else if (scoreDisplayMode !== 'manual') {
      ((details && details.items) || []).forEach(item =>
        snippets.push((item.node && item.node.snippet) || '')
      );
    }

    errorsObj[id] = { description, snippets };
  });

  const score = getTotalScore(successObj, errorsObj);

  return {
    audits,
    score,
    /**
     * @param {number} cutoff
     */
    isSuccess(cutoff) {
      assert.ok(
        score >= cutoff,
        `Score ${score} is smaller than expected cutoff score ${cutoff}`
      );
    },
    /**
     * @param {string?} audit
     * @returns {Record<string, auditInfo>}
     */
    success(audit) {
      return audit ? successObj[audit] : successObj;
    },
    /**
     * @param {string?} audit
     * @returns {Record<string, any>}
     */
    errors(audit) {
      return audit ? errorsObj[audit] : errorsObj;
    },
    /**
     * @returns {string}
     */
    errorString() {
      const errorList = [];

      for (const id in errorsObj) {
        const description = errorsObj[id].description;
        const snippets = errorsObj[id].snippets;
        errorList.push(`${description}:\n\t${snippets.join('\n\t')}`);
      }

      return errorList.join('\n\n');
    },
  };
}

/**
 *
 * @param {string} category
 * @param {number} minScore
 * @param {Array<string>} [skipAudits]
 * @returns {Promise<parsedLHResults>}
 */
async function assertScoreByCategory(category, minScore, skipAudits = []) {
  minScore = minScore || 100;

  category = category.toLowerCase();

  const config = getConfigByType(category, skipAudits);

  const results = await this.getLighthouseData(defaultFlags, config).then(
    parseLhResult
  );

  assert.ok(
    results.score >= minScore,
    `${category} score ${results.score} to be greater than ${minScore}`
  );

  return results;
}

/**
 *
 * @param {number} minScore
 * @param {Array<string>} [skipAudits]
 * @returns {Promise<parsedLHResults>}
 */
function assertPerformanceScore(minScore, skipAudits = []) {
  return this.assertScoreByCategory('performance', minScore, [
    ...skipAudits,
    'final-screenshot',
    'is-on-https',
    'screenshot-thumbnails',
  ]);
}

/**
 *
 * @param {number} minScore
 * @param {Array<string>} [skipAudits]
 * @returns {Promise<parsedLHResults>}
 */
function assertAccessibilityScore(minScore, skipAudits = []) {
  return this.assertScoreByCategory('accessibility', minScore, skipAudits);
}

/**
 *
 * @param {number} minScore
 * @param {Array<string>} skipAudits
 * @returns {Promise<parsedLHResults>}
 */
function assertBestPracticesScore(minScore, skipAudits = []) {
  return this.assertScoreByCategory('best-practices', minScore, skipAudits);
}

/**
 *
 * @param {number} minScore
 * @param {Array<string>} [skipAudits]
 * @returns {Promise<parsedLHResults>}
 */
function assertSeoScore(minScore, skipAudits = []) {
  return this.assertScoreByCategory('seo', minScore, skipAudits);
}

/**
 *
 * @param {number} minScore
 * @param {Array<string>} [skipAudits]
 * @returns {Promise<parsedLHResults>}
 */
function assertPwaScore(minScore, skipAudits = []) {
  return this.assertScoreByCategory('pwa', minScore, skipAudits);
}

/**
 *
 * @param {LH_Flags.Flags?} flags
 * @param {LH_Config.Json?} lhConfig
 * @returns {Promise<parsedLHResults>}
 * @legacy
 */
function runLighthouseAudit(flags, lhConfig) {
  return this.getLighthouseData(flags, lhConfig).then(parseLhResult);
}

/**
 * @param {{flags?: LH_Flags.Flags, config?: LH_Config.Json, ignore?:boolean}} options
 * @returns {Promise<{Object[]|[]>}
 */
async function a11yAudit(options = {}) {
  const { flags, config, ignore } = options;

  let violationsFilter; // function to filter violations
  if (typeof ignore === 'function') {
    violationsFilter = violation => !ignore(violation);
  } else if (Array.isArray(ignore)) {
    // e.g. ignore: ['html-has-lang']
    violationsFilter = violation => !ignore.includes(violation.id);
  } else {
    violationsFilter = () => true;
  }

  const result = await this.getLighthouseData(
    flags || defaultFlags,
    config || getConfigByType('accessibility')
  );

  // TODO: with node 12 use Array.prototype.flatMap
  return flatMap(
    result.artifacts.Accessibility.violations.filter(violationsFilter),
    violation => {
      const { nodes, ...violationData } = violation;
      return nodes.map(node => {
        return {
          ...violationData,
          auditId: violationData.id,
          selector: Array.isArray(node.target) ? node.target.join(' ') : '',
          path: node.path,
          snippet: node.snippet,
        };
      });
    }
  );
}

/**
 * @param {LH_Flags.Flags?} flags
 * @param {LH_Config.Json?} config
 * @returns {Promise<LH.RunnerResult>}
 */
async function getLighthouseData(flags, config) {
  if (!lighthouse) {
    throw new Error('Lighthouse requires a newer version of node');
  }
  const devtoolsPort = await this.getChromeDevtoolsPort();
  const options = { port: devtoolsPort, ...flags };
  const url = await this.url();

  return lighthouse(url, options, config);
}

module.exports = {
  a11yAudit,
  assertAccessibilityScore,
  assertBestPracticesScore,
  assertPerformanceScore,
  assertPwaScore,
  assertSeoScore,
  assertScoreByCategory,
  getLighthouseData,
  runLighthouseAudit,
};
<|endoftext|>


<commit_before>async function(args) {
/*
created_timestamp(-1)
base_component_id("app_editor_3")
is_app(true)
display_name("Editor App V3")
description("This will return the editor app V3")
logo_url("https://2.bp.blogspot.com/-6Hdixw3dFxk/WfSQOnB9lDI/AAAAAAAAFFc/84DRGgcwOpYBOgknkHQ-qmgxvFv1D-iHACLcBGAs/s1600/BracketsDarks.PNG")
load_once_from_file(true)
*/
    //
    // Hack city!!! Turn off the component cache so that we can enable hot reloading of components
    //
    isStaticHtmlPageApp = false
    //
    //
    //

    await loadV2("appEmbed")

    Vue.component("app_editor_3",
    {
      props: ['app_id', 'card_index'],
      template: `

{{app_component_name?"" + app_component_name.substring(0,30):""}}{{(app_component_name && ((app_component_name.length > 30))?"...":"")}}

                        <input  class='caption' style='display: inline-block;' v-if='edit_name' v-model='new_name'></input>
                        <button type=button class='btn btn-primary' style='margin-left: 10px' v-if='edit_name' v-on:click='(async function(){await rename(new_name)})()'>Save new name</button>

                            <select v-if='false' class="custom-select" v-model="selected_app" v-bind:onchange='load_new_app(selected_app)'>
                              <option value='' selected>Select an application to edit</option>
                              <option v-for='app in apps'
                                      v-bind:value="app.base_component_id"
                                      >{{app.display_name}}</option>
                            </select>
                            <button  type=button class='btn btn-primary'      v-on:click='chooseApp()'  >App</button>
                            <button  type=button class=' btn btn-secondary'   v-on:click='chooseCode()' >Code</button>
                            <button  type=button class=' btn btn-info'        v-on:click='chooseBoth()' >Both</button>
                            <button  type=button class=' btn btn-secondary'   v-on:click='copyAppMethod(base_component_id,null)' >Copy app</button>
                            <button  type=button class=' btn btn-info'        v-on:click='embedApp(base_component_id)' >Embed app</button>
                            <button  v-if='(editor_component != "editor_component") && (!read_only)' type=button class=' btn btn-secondary'   v-on:click='editAsText()' >Edit as text</button>

                        <appEmbed v-bind:base_component_id_arg='base_component_id'></appEmbed>

                          <component  v-bind:is="editor_component" v-if="editor_loaded" ref="editorComponentRef">
                                          <button v-if='!read_only'
                                                  v-bind:style="'visibility: ' + ((app_shown && code_shown)?'':'hidden')"
                                                  slot-scope="editor_component"
                                                  v-on:click='setTimeout(async function(){await save(base_component_id, code_id,null)},100)'
                                                  type="button" class="btn btn-primary btn-sm">

                                                      Save changes
                                         </button>
                          </component>

                                    {{show_new_tab_tooltip?"Open page in new browser tab (shareable :)":""}}
                                    {{show_open_app_tooltip?"Download as HTML app (emailable :)":""}}

                                ← → ↻
                                ❏

                                    <input  readonly size="40" style='font-size: 13px;'
                                        v-bind:value='"http://" + location.hostname + ":" + location.port + "/app/" + base_component_id + ".html"'></input>

                                ♨

                          <component  v-bind:is="app_component_name" v-if="app_loaded">
                            APP HERE
                          </component>

       `
       ,
       data: function() {
           return {
               editor_loaded:       false,
               selected_app:        '',
               editor_component:    null,
               app_loaded:          false,
               apps:               [],
               app_component_name:  null,
               base_component_id:   null,
               code_id:            "...",
               version: 0,
               app_width:           "33%",
               code_width:          "63%",
               app_shown:           true,
               code_shown:          true,
               read_only:           false,
               mode:                "edit",
               show_name:           true,
               edit_name:           false,
               new_name:            "",
               show_new_tab_tooltip:false,
               show_open_app_tooltip:false
           }
       }
       ,

       methods: {
            // ---------------------------------------------------------------
            //                         chooseApp
            //
            // This is called when the end user selects "app"
            // ---------------------------------------------------------------
            chooseApp: async function() {
                var mm = this
                this.code_width = "0%"
                this.code_shown = false

                this.app_width = "95%"
                this.app_shown = true

                this.mode      = "edit"

                var text = await this.$refs.editorComponentRef.getText()

                //
                // there may be a problem here - we have to make sure that we saved
                // the correct code_id which is supposed to be the parent code id, so we
                // have to make sure that we save it every time we save code
                //
                await this.save( this.base_component_id, this.code_id, text )
                //alert(1)
            },

            chooseCode: function() {
                var mm = this
                this.code_width = "95%"
                this.code_shown = true

                this.app_width = "0%"
                this.app_shown = false

                this.mode      = "edit"

                mm.load_app( this.base_component_id )
            },

            chooseBoth: function() {
                var mm = this
                this.code_width = "63%"
                this.code_shown = true

                this.app_width = "33%"
                this.app_shown = true

                this.mode      = "edit"
            },

            rename: async function(nn) {
                this.edit_name = false
                this.show_name = true

                nn = nn.replace(/[\W_]+/g,"_");
                await this.copyAppMethod( this.base_component_id , nn)
            },

            editAsText: async function() {
                var mm = this

                var text = await this.$refs.editorComponentRef.getText()
                //alert(text.indexOf("editors_old"))

                var eds = saveHelper.getValueOfCodeString(text, "editors")
                if (eds) {
                    text = saveHelper.deleteCodeString(text, "editors")
                    text = saveHelper.insertCodeString(text, "editors_old",eds)
                }

                await mm.save(   this.base_component_id,   this.code_id,   text   )

                await mm.load_new_app( this.base_component_id )
                //alert(text.indexOf("editors_old"))
            },

            embedApp: function(x) {
                var mm = this
                this.mode = "embed"
            }
            ,

            copyAppMethod: async function( appId , newAppId) {
                var mm = this
                var result = await callFunction(
                                    {
                                        driver_name: "copyApp",
                                        method_name: "copyAppshareApp"  }
                                        ,{
                                              base_component_id:    appId,
                                              new_app_id:           newAppId   })
                await mm.load_new_app( result.value.base_component_id )
                mm.$root.$emit('message', {
                                                type:               "insert_app_at",
                                                base_component_id:   result.value.base_component_id,
                                                card_index:          mm.card_index
                                            })

            }
            ,

           // ---------------------------------------------------------------
           //                           save
           //
           // This is called to save the currently edited code
           // ---------------------------------------------------------------
           save: async function( base_component_id, code_id , textIn) {
           //alert(code_id)
               console.log("1) AppEditor: save")
               var text =  textIn
               if (text == null) {
                    text = await this.$refs.editorComponentRef.getText()
               }
               console.log("5) AppEditor: getText done")

               var mm = this
               if (mm.read_only) {
                    return
               }
               //alert("Saving " + code_id)
               //alert("Saving " + text)
               //alert(base_component_id)
               var results = await callApp(
               {
                   driver_name:     "appEditorV2SaveCode",
                   method_name:     "saveCode"
               },
                   {
                        base_component_id:      base_component_id,
                        code_id:                code_id,
                        code:                   text,
                        options:                {
                                                    sub_components: Object.keys(dev_app_component_loaded)
                                                }
                   })
               //alert("Saved " + text)

               //alert("Reloading 2: " + JSON.stringify(results,null,2))
               //alert("Reloading 2: " + JSON.stringify(mm.base_component_id,null,2))
               mm.load_app( mm.base_component_id )
           },

           load_new_app: async function ( baseComponentId ) {
               var mm = this
               if ((!baseComponentId) || (baseComponentId == "") || (!mm)) {
                    return
               }
               dev_app_component_loaded = new Object()
               this.editor_loaded = false
               await this.load_app(baseComponentId)
           }
           ,

           // ---------------------------------------------------------------
           //                           load_app
           //
           // This loads the latest version of the code stream marked with
           // 'baseComponentId'
           // ---------------------------------------------------------------
           load_app: async function ( baseComponentId ) {
               console.log(`load_app:`)
               var mm = this
               if ((!baseComponentId) || (baseComponentId == "") || (!mm)) {
                    return
               }
                mm.selected_app = ""

               //
               // set up vars
               //
               mm.app_loaded            = false
               mm.base_component_id     = baseComponentId
               mm.app_component_name    = null

               //
               // read the code for the component that we are editing
               //
               var sql =    "select  id, cast(code as text)  as  code, editors  from  system_code  where " +
                            "        base_component_id = '" + baseComponentId + "'" +
                            "        and code_tag = 'LATEST' "

               var results = await callApp(
                   {
                        driver_name:    "systemFunctions2",
                        method_name:    "sql"
                   }
                   ,
                   {
                       sql: sql
                   })

               if (results) {
                   //alert(JSON.stringify(results,null,2))
                   if (results.length > 0) {
                       var editors2 = results[0].editors
                       var newEditor = null
                       if (editors2) {
                            var edd = eval("(" + editors2 + ")")
                            newEditor = edd[0]
                       }
                       var code = results[0].code
                       var codeId = results[0].id
                       //alert(code)
                       if (mm.editor_loaded && (mm.code != code)) {
                            //alert("changed: " + code)
                            //this.$refs.editorComponentRef.setText(code)
                            mm.code = code
                            mm.code_id = codeId
                       }
                       //alert(JSON.stringify(1,null,2))

                       if (!mm.editor_loaded) {
                            var editorName = "editor_component"
                            if (newEditor) {
                                 editorName = newEditor
                            }

                            await loadV2(editorName,{text: code})
                            mm.editor_loaded = true
                            mm.editor_component = editorName
                       }

                       this.read_only = saveHelper.getValueOfCodeString(code, "read_only")

                   }

                   var results = await callApp( {code_id:    codeId },{})
                   mm.app_loaded = true
                   mm.baseComponentId = baseComponentId
//zzz
                   setTimeout(async function() {
                       mm.app_component_name = baseComponentId
                       //alert(results.name + " loaded")
                       mm.$refs.editorComponentRef.setText(code)

                   },500)
               }

               }

       },

       mounted: async function () {
        console.log(`appEditor: mounted: this.app_id = ${this.app_id}`)
           var mm = this
           //alert(this.app_id)
            if (this.app_id) {
                //alert(this.app_id)
                //this.base_component_id = app_id

                component_loaded[this.app_id]           = false
                dev_app_component_loaded[this.app_id]   = false
                component_cache[this.app_id]            = null

                await this.load_app(this.app_id)
                //alert(Object.keys(component_cache[this.app_id]))
            } else {
                var result = await callApp( {
                                        driver_name:  "systemFunctions",
                                        method_name:  "get_apps_list"  } ,{})

                mm.apps = result
            }
       }
       })
       return {name: "app_editor"}

}
<commit_msg>When renaming an app start with a blank name<commit_after>async function(args) {
/*
created_timestamp(-1)
base_component_id("app_editor_3")
is_app(true)
display_name("Editor App V3")
description("This will return the editor app V3")
logo_url("https://2.bp.blogspot.com/-6Hdixw3dFxk/WfSQOnB9lDI/AAAAAAAAFFc/84DRGgcwOpYBOgknkHQ-qmgxvFv1D-iHACLcBGAs/s1600/BracketsDarks.PNG")
load_once_from_file(true)
*/
    //
    // Hack city!!! Turn off the component cache so that we can enable hot reloading of components
    //
    isStaticHtmlPageApp = false
    //
    //
    //

    await loadV2("appEmbed")

    Vue.component("app_editor_3",
    {
      props: ['app_id', 'card_index'],
      template: `

{{app_component_name?"" + app_component_name.substring(0,30):""}}{{(app_component_name && ((app_component_name.length > 30))?"...":"")}}

                        <input  class='caption' style='display: inline-block;' v-if='edit_name' v-model='new_name'></input>
                        <button type=button class='btn btn-primary' style='margin-left: 10px' v-if='edit_name' v-on:click='(async function(){await rename(new_name)})()'>Save new name</button>

                            <select v-if='false' class="custom-select" v-model="selected_app" v-bind:onchange='load_new_app(selected_app)'>
                              <option value='' selected>Select an application to edit</option>
                              <option v-for='app in apps'
                                      v-bind:value="app.base_component_id"
                                      >{{app.display_name}}</option>
                            </select>
                            <button  type=button class='btn btn-primary'      v-on:click='chooseApp()'  >App</button>
                            <button  type=button class=' btn btn-secondary'   v-on:click='chooseCode()' >Code</button>
                            <button  type=button class=' btn btn-info'        v-on:click='chooseBoth()' >Both</button>
                            <button  type=button class=' btn btn-secondary'   v-on:click='copyAppMethod(base_component_id,null)' >Copy app</button>
                            <button  type=button class=' btn btn-info'        v-on:click='embedApp(base_component_id)' >Embed app</button>
                            <button  v-if='(editor_component != "editor_component") && (!read_only)' type=button class=' btn btn-secondary'   v-on:click='editAsText()' >Edit as text</button>

                        <appEmbed v-bind:base_component_id_arg='base_component_id'></appEmbed>

                          <component  v-bind:is="editor_component" v-if="editor_loaded" ref="editorComponentRef">
                                          <button v-if='!read_only'
                                                  v-bind:style="'visibility: ' + ((app_shown && code_shown)?'':'hidden')"
                                                  slot-scope="editor_component"
                                                  v-on:click='setTimeout(async function(){await save(base_component_id, code_id,null)},100)'
                                                  type="button" class="btn btn-primary btn-sm">

                                                      Save changes
                                         </button>
                          </component>

                                    {{show_new_tab_tooltip?"Open page in new browser tab (shareable :)":""}}
                                    {{show_open_app_tooltip?"Download as HTML app (emailable :)":""}}

                                ← → ↻
                                ❏

                                    <input  readonly size="40" style='font-size: 13px;'
                                        v-bind:value='"http://" + location.hostname + ":" + location.port + "/app/" + base_component_id + ".html"'></input>

                                ♨

                          <component  v-bind:is="app_component_name" v-if="app_loaded">
                            APP HERE
                          </component>

       `
       ,
       data: function() {
           return {
               editor_loaded:       false,
               selected_app:        '',
               editor_component:    null,
               app_loaded:          false,
               apps:               [],
               app_component_name:  null,
               base_component_id:   null,
               code_id:            "...",
               version: 0,
               app_width:           "33%",
               code_width:          "63%",
               app_shown:           true,
               code_shown:          true,
               read_only:           false,
               mode:                "edit",
               show_name:           true,
               edit_name:           false,
               new_name:            "",
               show_new_tab_tooltip:false,
               show_open_app_tooltip:false
           }
       }
       ,

       methods: {
            // ---------------------------------------------------------------
            //                         chooseApp
            //
            // This is called when the end user selects "app"
            // ---------------------------------------------------------------
            chooseApp: async function() {
                var mm = this
                this.code_width = "0%"
                this.code_shown = false

                this.app_width = "95%"
                this.app_shown = true

                this.mode      = "edit"

                var text = await this.$refs.editorComponentRef.getText()

                //
                // there may be a problem here - we have to make sure that we saved
                // the correct code_id which is supposed to be the parent code id, so we
                // have to make sure that we save it every time we save code
                //
                await this.save( this.base_component_id, this.code_id, text )
                //alert(1)
            },

            chooseCode: function() {
                var mm = this
                this.code_width = "95%"
                this.code_shown = true

                this.app_width = "0%"
                this.app_shown = false

                this.mode      = "edit"

                mm.load_app( this.base_component_id )
            },

            chooseBoth: function() {
                var mm = this
                this.code_width = "63%"
                this.code_shown = true

                this.app_width = "33%"
                this.app_shown = true

                this.mode      = "edit"
            },

            rename: async function(nn) {
                this.edit_name = false
                this.show_name = true

                nn = nn.replace(/[\W_]+/g,"_");
                await this.copyAppMethod( this.base_component_id , nn)
                this.new_name = ""
            },

            editAsText: async function() {
                var mm = this

                var text = await this.$refs.editorComponentRef.getText()
                //alert(text.indexOf("editors_old"))

                var eds = saveHelper.getValueOfCodeString(text, "editors")
                if (eds) {
                    text = saveHelper.deleteCodeString(text, "editors")
                    text = saveHelper.insertCodeString(text, "editors_old",eds)
                }

                await mm.save(   this.base_component_id,   this.code_id,   text   )

                await mm.load_new_app( this.base_component_id )
                //alert(text.indexOf("editors_old"))
            },

            embedApp: function(x) {
                var mm = this
                this.mode = "embed"
            }
            ,

            copyAppMethod: async function( appId , newAppId) {
                var mm = this
                var result = await callFunction(
                                    {
                                        driver_name: "copyApp",
                                        method_name: "copyAppshareApp"  }
                                        ,{
                                              base_component_id:    appId,
                                              new_app_id:           newAppId   })
                await mm.load_new_app( result.value.base_component_id )
                mm.$root.$emit('message', {
                                                type:               "insert_app_at",
                                                base_component_id:   result.value.base_component_id,
                                                card_index:          mm.card_index
                                            })

            }
            ,

           // ---------------------------------------------------------------
           //                           save
           //
           // This is called to save the currently edited code
           // ---------------------------------------------------------------
           save: async function( base_component_id, code_id , textIn) {
           //alert(code_id)
               console.log("1) AppEditor: save")
               var text =  textIn
               if (text == null) {
                    text = await this.$refs.editorComponentRef.getText()
               }
               console.log("5) AppEditor: getText done")

               var mm = this
               if (mm.read_only) {
                    return
               }
               //alert("Saving " + code_id)
               //alert("Saving " + text)
               //alert(base_component_id)
               var results = await callApp(
               {
                   driver_name:     "appEditorV2SaveCode",
                   method_name:     "saveCode"
               },
                   {
                        base_component_id:      base_component_id,
                        code_id:                code_id,
                        code:                   text,
                        options:                {
                                                    sub_components: Object.keys(dev_app_component_loaded)
                                                }
                   })
               //alert("Saved " + text)

               //alert("Reloading 2: " + JSON.stringify(results,null,2))
               //alert("Reloading 2: " + JSON.stringify(mm.base_component_id,null,2))
               mm.load_app( mm.base_component_id )
           },

           load_new_app: async function ( baseComponentId ) {
               var mm = this
               if ((!baseComponentId) || (baseComponentId == "") || (!mm)) {
                    return
               }
               dev_app_component_loaded = new Object()
               this.editor_loaded = false
               await this.load_app(baseComponentId)
           }
           ,

           // ---------------------------------------------------------------
           //                           load_app
           //
           // This loads the latest version of the code stream marked with
           // 'baseComponentId'
           // ---------------------------------------------------------------
           load_app: async function ( baseComponentId ) {
               console.log(`load_app:`)
               var mm = this
               if ((!baseComponentId) || (baseComponentId == "") || (!mm)) {
                    return
               }
                mm.selected_app = ""

               //
               // set up vars
               //
               mm.app_loaded            = false
               mm.base_component_id     = baseComponentId
               mm.app_component_name    = null

               //
               // read the code for the component that we are editing
               //
               var sql =    "select  id, cast(code as text)  as  code, editors  from  system_code  where " +
                            "        base_component_id = '" + baseComponentId + "'" +
                            "        and code_tag = 'LATEST' "

               var results = await callApp(
                   {
                        driver_name:    "systemFunctions2",
                        method_name:    "sql"
                   }
                   ,
                   {
                       sql: sql
                   })

               if (results) {
                   //alert(JSON.stringify(results,null,2))
                   if (results.length > 0) {
                       var editors2 = results[0].editors
                       var newEditor = null
                       if (editors2) {
                            var edd = eval("(" + editors2 + ")")
                            newEditor = edd[0]
                       }
                       var code = results[0].code
                       var codeId = results[0].id
                       //alert(code)
                       if (mm.editor_loaded && (mm.code != code)) {
                            //alert("changed: " + code)
                            //this.$refs.editorComponentRef.setText(code)
                            mm.code = code
                            mm.code_id = codeId
                       }
                       //alert(JSON.stringify(1,null,2))

                       if (!mm.editor_loaded) {
                            var editorName = "editor_component"
                            if (newEditor) {
                                 editorName = newEditor
                            }

                            await loadV2(editorName,{text: code})
                            mm.editor_loaded = true
                            mm.editor_component = editorName
                       }

                       this.read_only = saveHelper.getValueOfCodeString(code, "read_only")

                   }

                   var results = await callApp( {code_id:    codeId },{})
                   mm.app_loaded = true
                   mm.baseComponentId = baseComponentId
//zzz
                   setTimeout(async function() {
                       mm.app_component_name = baseComponentId
                       //alert(results.name + " loaded")
                       mm.$refs.editorComponentRef.setText(code)

                   },500)
               }

               }

       },

       mounted: async function () {
        console.log(`appEditor: mounted: this.app_id = ${this.app_id}`)
           var mm = this
           //alert(this.app_id)
            if (this.app_id) {
                //alert(this.app_id)
                //this.base_component_id = app_id

                component_loaded[this.app_id]           = false
                dev_app_component_loaded[this.app_id]   = false
                component_cache[this.app_id]            = null

                await this.load_app(this.app_id)
                //alert(Object.keys(component_cache[this.app_id]))
            } else {
                var result = await callApp( {
                                        driver_name:  "systemFunctions",
                                        method_name:  "get_apps_list"  } ,{})

                mm.apps = result
            }
       }
       })
       return {name: "app_editor"}

}
<|endoftext|>


<commit_before>import { Syncher } from 'service-framework/dist/Syncher';
import URI from 'urijs';
import position from './position';
import Search from '../utils/Search';
import IdentityManager from 'service-framework/dist/IdentityManager';
import { Discovery } from 'service-framework/dist/Discovery';
import { callbackify } from 'util';

class LocationHypertyFactory {

  constructor(hypertyURL, bus, config) {
    let uri = new URI(hypertyURL);
    this.objectDescURL = `hyperty-catalogue://catalogue.${uri.hostname()}/.well-known/dataschema/Context`;
    this.syncher = new Syncher(hypertyURL, bus, config);
    this.identityManager = new IdentityManager(hypertyURL, config.runtimeURL, bus);
    this.discovery = new Discovery(hypertyURL, config.runtimeURL, bus);
    this.search = new Search(this.discovery, this.identityManager);
    this.currentPosition = null;
    this.identity = null;
    this.bus = bus;
    this.hypertyURL = hypertyURL;
    this.reporter = null;
    this.watchID = null;

  }

  _getRegisteredUser() {
    let _this = this;

    return new Promise((resolve, reject) => {
      _this.identityManager.discoverUserRegistered().then((identity) => {
        console.log('[LocationReporter] GET MY IDENTITY:', identity);
        resolve(identity);
      }).catch((error) => {
        console.error('[LocationReporter] ERROR:', error);
        reject(error);
      });
    });

  }

  _resumeReporters() {
    let _this = this;
    //debugger;
    return new Promise((resolve, reject) => {
      _this.syncher.resumeReporters({store: true}).then((reporters) => {
        console.log('[LocationReporter] Reporters resumed', reporters);

        let reportersList = Object.keys(reporters);

        if (reportersList.length  > 0) {

          _this._getRegisteredUser().then((identity) => {

            reportersList.forEach((dataObjectReporterURL) => {
              //debugger;
              console.log(identity);
              _this.identity = identity;
              console.log('[LocationReporter] ', dataObjectReporterURL);
              console.log('[LocationReporter]', reporters[dataObjectReporterURL]);

              if (identity.userURL == reporters[dataObjectReporterURL].metadata.subscriberUsers[0] && reporters[dataObjectReporterURL].metadata.name == 'location') {
                //debugger;
                _this.reporter = reporters[dataObjectReporterURL];
                _this.reporter.onSubscription((event) => event.accept());
                return resolve(true);
              } else {
                return resolve(false);
              }
            });
          });
        } else {
          return resolve(false);
        }
      }).catch((reason) => {
        console.info('[LocationReporter] Reporters:', reason);
      });
    });
  }

  //FOR invite checkin  -> hyperty://sharing-cities-dsm/checkin-rating
  invite(observer) {

    let _this = this;
    _this.reporter.inviteObservers([observer]);
  }

  watchMyLocation(callback) {

    function success(pos) {
      var crd = pos.coords;
      callback(crd);
    }

    function error(err) {
      console.warn('ERROR(' + err.code + '): ' + err.message);
    }

    const options = {
      enableHighAccuracy: true

      // timeout: 5000,
      // maximumAge: 0
    };

    this.watchID = navigator.geolocation.watchPosition(success, error, options);
  }

  removeWatchMyLocation() {
    navigator.geolocation.clearWatch(this.watchID);
  }

  getLocation() {
    return this.currentPosition;
  }

  startPositionBroadcast() {
    let _this = this;
    if (_this.reporter == null) {
      _this.syncher.create(_this.objectDescURL, [], position(), true, false, 'location', {}, { resources: ['location-context'] })
        .then((reporter) => {
          _this.reporter = reporter;
          console.log('[LocationReporter]  DataObjectReporter', _this.reporter);
          reporter.onSubscription((event) => event.accept());
          _this.search.myIdentity().then(identity => {
            _this.identity = identity;
            _this.broadcastMyPosition();
          });
        });
    } else {
      _this.broadcastMyPosition();
    }

  }

  initPosition() {
    //debugger;
    let _this = this;
    if (_this.reporter == null) {
      _this.syncher.create(_this.objectDescURL, [], position(), true, false, 'location', {}, { resources: ['location-context'] })
        .then((reporter) => {
          _this.reporter = reporter;
          console.log('[LocationReporter]  DataObjectReporter', _this.reporter);
          reporter.onSubscription((event) => event.accept());
          _this.search.myIdentity().then(identity => {
            _this.identity = identity;
            _this.setCurrentPosition();
          });
      });
    } else {
      _this.setCurrentPosition();
    }
}

  setCurrentPosition() {
    let _this = this;
    navigator.geolocation.watchPosition((position) => {
      console.log('[LocationReporter] my position: ', position);
      _this.currentPosition = position;
      //debugger;
    });
  }

  broadcastMyPosition() {
    let _this = this;
    navigator.geolocation.watchPosition((position) => {
      console.log('[LocationReporter] my position: ', position);
      _this.currentPosition = position;
      _this.reporter.data.values = [
        { name: 'latitude', unit: 'lat', value: position.coords.latitude},
        { name: 'longitude', unit: 'lon', value: position.coords.longitude }
      ];
      _this.reporter.data.time = position.timestamp;
      _this.reporter.data.tag = _this.identity.preferred_username;
      //debugger;
    });
  }

  updateLocation() {
    let _this = this;
    let latitude = _this.currentPosition.coords.latitude;
    let longitude = _this.currentPosition.coords.longitude;
    _this.reporter.data.values = [
      { name: 'latitude', unit: 'lat', value: latitude },
      { name: 'longitude', unit: 'lon', value: longitude }
    ];
    _this.reporter.data.time = _this.currentPosition.timestamp;
    _this.reporter.data.tag = _this.identity.preferred_username;
  }

  checkin(spotId) {
    let _this = this;
    let latitude = _this.currentPosition.coords.latitude;
    let longitude = _this.currentPosition.coords.longitude;
    _this.reporter.data.values = [
      { name: 'latitude', unit: 'lat', value: latitude },
      { name: 'longitude', unit: 'lon', value: longitude },
      { name: 'checkin', unit: 'checkin', value: spotId }
    ];

  }

  // can call with 'data://sharing-cities-dsm/shops'
  retrieveSpots(spotsURL) {

    return new Promise((resolve) => {
      let _this = this;

      let createMessage = {
        type: 'forward', to: spotsURL, from: _this.hypertyURL,
        body: {
          from: _this.hypertyURL,
          type: 'read'
        }
      };

      console.log('location-reporter-retrieveSpots()', createMessage);

      _this.bus.postMessage(createMessage, (reply) => {
        resolve(reply);
        console.log('location-reporter-retrieveSpots() reply: ', reply);
      });

    });

  }

}

export default function activate(hypertyURL, bus, config) {
  return {
    name: 'LocationReporter',
    instance: new LocationHypertyFactory(hypertyURL, bus, config)
  };
}
<commit_msg>update resume reporter location<commit_after>import { Syncher } from 'service-framework/dist/Syncher';
import URI from 'urijs';
import position from './position';
import Search from '../utils/Search';
import IdentityManager from 'service-framework/dist/IdentityManager';
import { Discovery } from 'service-framework/dist/Discovery';
import { callbackify } from 'util';

class LocationHypertyFactory {

  constructor(hypertyURL, bus, config) {
    let uri = new URI(hypertyURL);
    this.objectDescURL = `hyperty-catalogue://catalogue.${uri.hostname()}/.well-known/dataschema/Context`;
    this.syncher = new Syncher(hypertyURL, bus, config);
    this.identityManager = new IdentityManager(hypertyURL, config.runtimeURL, bus);
    this.discovery = new Discovery(hypertyURL, config.runtimeURL, bus);
    this.search = new Search(this.discovery, this.identityManager);
    this.currentPosition = null;
    this.identity = null;
    this.bus = bus;
    this.hypertyURL = hypertyURL;
    this.reporter = null;
    this.watchID = null;

  }

  _getRegisteredUser() {
    let _this = this;

    return new Promise((resolve, reject) => {
      _this.identityManager.discoverUserRegistered().then((identity) => {
        console.log('[LocationReporter] GET MY IDENTITY:', identity);
        resolve(identity);
      }).catch((error) => {
        console.error('[LocationReporter] ERROR:', error);
        reject(error);
      });
    });

  }

  _resumeReporters() {
    let _this = this;
    //debugger;
    return new Promise((resolve, reject) => {
      _this.syncher.resumeReporters({store: true}).then((reporters) => {
        console.log('[LocationReporter] Reporters resumed', reporters);

        let reportersList = Object.keys(reporters);

        if (reportersList.length  > 0) {

          _this._getRegisteredUser().then((identity) => {

            reportersList.forEach((dataObjectReporterURL) => {
              //debugger;
              console.log(identity);
              _this.identity = identity;
              console.log('[LocationReporter] ', dataObjectReporterURL);
              console.log('[LocationReporter]', reporters[dataObjectReporterURL]);

              if (identity.userURL == reporters[dataObjectReporterURL].metadata.subscriberUsers[0] && reporters[dataObjectReporterURL].metadata.name == 'location') {
                //debugger;
                _this.reporter = reporters[dataObjectReporterURL];
                _this.reporter.onSubscription((event) => event.accept());
                return resolve(true);
              }
            });
            return resolve(false);
          });
        } else {
          return resolve(false);
        }
      }).catch((reason) => {
        console.info('[LocationReporter] Reporters:', reason);
      });
    });
  }

  //FOR invite checkin  -> hyperty://sharing-cities-dsm/checkin-rating
  invite(observer) {

    let _this = this;
    _this.reporter.inviteObservers([observer]);
  }

  watchMyLocation(callback) {

    function success(pos) {
      var crd = pos.coords;
      callback(crd);
    }

    function error(err) {
      console.warn('ERROR(' + err.code + '): ' + err.message);
    }

    const options = {
      enableHighAccuracy: true

      // timeout: 5000,
      // maximumAge: 0
    };

    this.watchID = navigator.geolocation.watchPosition(success, error, options);
  }

  removeWatchMyLocation() {
    navigator.geolocation.clearWatch(this.watchID);
  }

  getLocation() {
    return this.currentPosition;
  }

  startPositionBroadcast() {
    let _this = this;
    if (_this.reporter == null) {
      _this.syncher.create(_this.objectDescURL, [], position(), true, false, 'location', {}, { resources: ['location-context'] })
        .then((reporter) => {
          _this.reporter = reporter;
          console.log('[LocationReporter]  DataObjectReporter', _this.reporter);
          reporter.onSubscription((event) => event.accept());
          _this.search.myIdentity().then(identity => {
            _this.identity = identity;
            _this.broadcastMyPosition();
          });
        });
    } else {
      _this.broadcastMyPosition();
    }

  }

  initPosition() {
    //debugger;
    let _this = this;
    if (_this.reporter == null) {
      _this.syncher.create(_this.objectDescURL, [], position(), true, false, 'location', {}, { resources: ['location-context'] })
        .then((reporter) => {
          _this.reporter = reporter;
          console.log('[LocationReporter]  DataObjectReporter', _this.reporter);
          reporter.onSubscription((event) => event.accept());
          _this.search.myIdentity().then(identity => {
            _this.identity = identity;
            _this.setCurrentPosition();
          });
      });
    } else {
      _this.setCurrentPosition();
    }
}

  setCurrentPosition() {
    let _this = this;
    navigator.geolocation.watchPosition((position) => {
      console.log('[LocationReporter] my position: ', position);
      _this.currentPosition = position;
      //debugger;
    });
  }

  broadcastMyPosition() {
    let _this = this;
    navigator.geolocation.watchPosition((position) => {
      console.log('[LocationReporter] my position: ', position);
      _this.currentPosition = position;
      _this.reporter.data.values = [
        { name: 'latitude', unit: 'lat', value: position.coords.latitude},
        { name: 'longitude', unit: 'lon', value: position.coords.longitude }
      ];
      _this.reporter.data.time = position.timestamp;
      _this.reporter.data.tag = _this.identity.preferred_username;
      //debugger;
    });
  }

  updateLocation() {
    let _this = this;
    let latitude = _this.currentPosition.coords.latitude;
    let longitude = _this.currentPosition.coords.longitude;
    _this.reporter.data.values = [
      { name: 'latitude', unit: 'lat', value: latitude },
      { name: 'longitude', unit: 'lon', value: longitude }
    ];
    _this.reporter.data.time = _this.currentPosition.timestamp;
    _this.reporter.data.tag = _this.identity.preferred_username;
  }

  checkin(spotId) {
    let _this = this;
    let latitude = _this.currentPosition.coords.latitude;
    let longitude = _this.currentPosition.coords.longitude;
    _this.reporter.data.values = [
      { name: 'latitude', unit: 'lat', value: latitude },
      { name: 'longitude', unit: 'lon', value: longitude },
      { name: 'checkin', unit: 'checkin', value: spotId }
    ];

  }

  // can call with 'data://sharing-cities-dsm/shops'
  retrieveSpots(spotsURL) {

    return new Promise((resolve) => {
      let _this = this;

      let createMessage = {
        type: 'forward', to: spotsURL, from: _this.hypertyURL,
        body: {
          from: _this.hypertyURL,
          type: 'read'
        }
      };

      console.log('location-reporter-retrieveSpots()', createMessage);

      _this.bus.postMessage(createMessage, (reply) => {
        resolve(reply);
        console.log('location-reporter-retrieveSpots() reply: ', reply);
      });

    });

  }

}

export default function activate(hypertyURL, bus, config) {
  return {
    name: 'LocationReporter',
    instance: new LocationHypertyFactory(hypertyURL, bus, config)
  };
}
<|endoftext|>


<commit_before>var utils   = require('./utils'),
    glob    = require('glob'),
    async   = require('async'),
    fileLib = require("node-fs"),
    path    = require('path'),
    _       = require('lodash'),
    fs      = require('fs'),
    mkdirp  = require('mkdirp');

var basePath = process.cwd(),
    pathSep  = '/',
    pathLib  = path;

function installFile(f, key, paths, dep, callback) {

  var f_s,  // The path for the file to be moved
      f_name, // The full path for the file to be moved
      path,   // The path for the new file location
      f_name_new; // The new file name, if we are mapping to a new name

    // If the dependency is an object, it must
    // be a mapping, so configure things to rename
    // the file
    if(_.isObject(f)){
      for(var dep_key in f) {
        f_s = dep_key;
        f_name_new = f[f_s];
      }
    } else {
      f_s = f;
    }

    // If the file path doesn't include the current location, add it
    f_name = f_s.indexOf(basePath) === 0 ? f_s : basePath + pathSep + f_s;

	// add subdirectories if glob are "**"
    var subDir = '';

    if(!f_name_new) {
        last = dep.match(/([a-z|A-Z]*)\/\*\*/i)
        if (last && typeof last[1] !== undefined) {
            f_name_helper = f_name.split(last[1]);
            subDir = (f_name_helper[1] != '')
            ? pathLib.dirname(f_name_helper[1])
            : f_name_helper[1];
        }
    }

    // If the configured paths is a map, use the path for the given file extension
    if( paths.all ) {
        path = paths.all + pathSep + key + subDir;

        mkdirp.sync(
            pathLib.normalize(basePath + pathSep + path),
            0755
        );
    } else {
        // Determine the path by the file extension type
        path = paths[utils.getExtension(f_name)] +  pathSep + key + subDir;

        mkdirp.sync(
            pathLib.normalize(basePath + pathSep + path + pathSep + subDir),
            0755
        );
    }

    var name = f_name_new ? f_name_new : pathLib.basename(f_name);
    var f_path = basePath + pathSep + path + pathSep + name;

    // For mapped files, create the directory if it doesn't exist
    if (f_name_new && !fileLib.existsSync(pathLib.normalize(pathLib.dirname(f_path)))) {
        fileLib.mkdirSync(pathLib.normalize(pathLib.dirname(f_path)));
    }

    // If it is a directory lets try to read from package.json file
    if( fs.lstatSync( f_name ).isDirectory() ) {

        var packagejson = f_name + pathSep + "package.json";

        // we want the build to continue as default if case something fails
        try {
            // read package.json file
            var file = fs.readFileSync(packagejson).toString('ascii')

            // parse file
            var filedata = JSON.parse(file);

            // path to file from main property inside package.json
            var mainpath = f_name + pathSep + filedata.main;

            // if we have a file reference on package.json to main property and it is a file
            if( fs.lstatSync( mainpath ).isFile() ) {

                f_name = mainpath;
                // Update the output path with the correct file extension
                if( !paths.all ) {
                    path = paths[getExtension(mainpath)];
                }
                f_path = basePath + pathSep + path + pathSep + filedata.main;
            }

        }
        catch( error ) {
            // We wont need to show log error, if package.json doesnt exist default to download folder
            // console.log(error);
        }
    }

    if( !fs.lstatSync( f_name ).isDirectory() ) {
        utils.copyFile(f_name, f_path, function(error) {
            if(!error) {
                console.log(('\t' + key + ' : ' + f_path).green);
            } else {
                console.log(('Error\t' + f + ' : ' + f_path).red);
                console.log('\t\t' + error);
            }
            callback(error);
        });
    } else {
        callback();
    }
}

exports.installDependency = function installDependency(deps, key, cfg, paths, callback) {
    var base, other;

    // Look for an overriden source
    if(cfg.sources && cfg.sources[key]){
        // local path, so should work
        deps = cfg.sources[key];
    }
    else {
        deps = deps.split(',');
    }

    // Check for mapping which will map old file names to new ones
    if(deps.mapping) {
      deps = deps.mapping;
    }

    // Ensure we always are dealing with an array
    if(!_.isArray(deps)) {
        deps = [ deps ];
    }

    // Install each dependency
    async.each(deps, function(dep, callback) {

      // If the file is an object, it is for mapping (renaming) the source
      // file to a new filename in the destination. Because of this, it
      // does not make sense to do a file glob, just immediately install
      // the file
      if(_.isObject(dep)) {
        installFile(dep, key, paths, dep, callback);
      } else {
        glob(dep, function(err, files) {
          if(err) {
            console.log(('Error globbing \t' + key + ' : ' + dep).red);
            console.log(('\t\t' + err).red);
          } else {
            async.each(files, function(f, callback) {
              installFile(f, key, paths, dep, callback);
            }, callback);
          }
        });
      }
    }, callback);
};

exports.removeComponentsDir = function(callback) {
    utils.deleteFolderRecursive(basePath + pathSep + 'bower_components');
    callback();
}
<commit_msg>Fix for creating empty folders<commit_after>var utils = require('./utils'),
    glob = require('glob'),
    async = require('async'),
    fileLib = require("node-fs"),
    path = require('path'),
    _ = require('lodash'),
    fs = require('fs'),
    mkdirp = require('mkdirp');

var basePath = process.cwd(),
    pathSep = '/',
    pathLib = path;

function installFile(f, key, paths, dep, callback) {

    var f_s, // The path for the file to be moved
    f_name, // The full path for the file to be moved
    path, // The path for the new file location
    f_name_new; // The new file name, if we are mapping to a new name

    // If the dependency is an object, it must
    // be a mapping, so configure things to rename
    // the file
    if (_.isObject(f)) {
        for (var dep_key in f) {
            f_s = dep_key;
            f_name_new = f[f_s];
        }
    } else {
        f_s = f;
    }

    // If the file path doesn't include the current location, add it
    f_name = f_s.indexOf(basePath) === 0 ? f_s : basePath + pathSep + f_s;

    // add subdirectories if glob are "**"
    var subDir = '';

    if (!f_name_new) {
        last = dep.match(/([a-z|A-Z]*)\/\*\*/i)
        if (last && typeof last[1] !== undefined) {
            f_name_helper = f_name.split(last[1]);
            subDir = (f_name_helper[1] != '') ? pathLib.dirname(f_name_helper[1]) : f_name_helper[1];
        }
    }

    // If the configured paths is a map, use the path for the given file extension
    if (paths.all) {
        path = paths.all + pathSep + key + subDir;

        mkdirp.sync(
        	pathLib.normalize(basePath + pathSep + path),
            0755
        );
    } else {
        // Determine the path by the file extension type
        path = paths[utils.getExtension(f_name)];

        if (path) {
            path += pathSep + key + subDir

            mkdirp.sync(
                pathLib.normalize(basePath + pathSep + path),
                0755
            );
		}
    }

    var name = f_name_new ? f_name_new : pathLib.basename(f_name);
    var f_path = basePath + pathSep + path + pathSep + name;

    // For mapped files, create the directory if it doesn't exist
    if (f_name_new && !fileLib.existsSync(pathLib.normalize(pathLib.dirname(f_path)))) {
        fileLib.mkdirSync(pathLib.normalize(pathLib.dirname(f_path)));
    }

    // If it is a directory lets try to read from package.json file
    if (fs.lstatSync(f_name).isDirectory()) {

        var packagejson = f_name + pathSep + "package.json";

        // we want the build to continue as default if case something fails
        try {
            // read package.json file
            var file = fs.readFileSync(packagejson).toString('ascii')

            // parse file
            var filedata = JSON.parse(file);

            // path to file from main property inside package.json
            var mainpath = f_name + pathSep + filedata.main;

            // if we have a file reference on package.json to main property and it is a file
            if (fs.lstatSync(mainpath).isFile()) {

                f_name = mainpath;
                // Update the output path with the correct file extension
                if (!paths.all) {
                    path = paths[getExtension(mainpath)];
                }
                f_path = basePath + pathSep + path + pathSep + filedata.main;
            }

        } catch (error) {
            // We wont need to show log error, if package.json doesnt exist default to download folder
            // console.log(error);
        }
    }

    if (!fs.lstatSync(f_name).isDirectory()) {
        utils.copyFile(f_name, f_path, function(error) {
            if (!error) {
                console.log(('\t' + key + ' : ' + f_path).green);
            } else {
                console.log(('Error\t' + f + ' : ' + f_path).red);
                console.log('\t\t' + error);
            }
            callback(error);
        });
    } else {
        callback();
    }
}

exports.installDependency = function installDependency(deps, key, cfg, paths, callback) {
    var base, other;

    // Look for an overriden source
    if (cfg.sources && cfg.sources[key]) {
        // local path, so should work
        deps = cfg.sources[key];
    } else {
        deps = deps.split(',');
    }

    // Check for mapping which will map old file names to new ones
    if (deps.mapping) {
        deps = deps.mapping;
    }

    // Ensure we always are dealing with an array
    if (!_.isArray(deps)) {
        deps = [deps];
    }

    // Install each dependency
    async.each(deps, function(dep, callback) {

        // If the file is an object, it is for mapping (renaming) the source
        // file to a new filename in the destination. Because of this, it
        // does not make sense to do a file glob, just immediately install
        // the file
        if (_.isObject(dep)) {
            installFile(dep, key, paths, dep, callback);
        } else {
            glob(dep, function(err, files) {
                if (err) {
                    console.log(('Error globbing \t' + key + ' : ' + dep).red);
                    console.log(('\t\t' + err).red);
                } else {
                    async.each(files, function(f, callback) {
                        installFile(f, key, paths, dep, callback);
                    }, callback);
                }
            });
        }
    }, callback);
};

exports.removeComponentsDir = function(callback) {
    utils.deleteFolderRecursive(basePath + pathSep + 'bower_components');
    callback();
}
<|endoftext|>