<commit_before>export default {

  langName: `English`,
  langCode: `en`,

  header: {},

  footer: {
    header:    `Cliff Effects Tool`,
    cfbCredit: [
      `Made with `,
      { name: `__heartIcon__` },
      ` by Code for Boston`,
    ],
  },

  homePage: {
    appName:          `Cliff Effects Tool`,
    prototypeNote:    `GUIDANCE PROTOYPE*`,
    cautionaryNote:   `*This is a prototype and should not be used to make financial decisions`,
    toFirstInputPage: `Get Started`,
    toAboutPage:      `Learn More`,
  },

  aboutPage: {
    aboutPageHeader: `About the Cliff Effects Tool`,

    whatForHeader:        `What is this tool for?`,
    whatForImportantNote: [
      {
        name: `__importantNote__`,
        text: `Important Note:`,
      },
      `This application is a minimum viable product. It should not be used as the sole tool to understand a client's SNAP or Section 8 financial situation, or for any other public assistance program.`,
    ],
    whatFor: [
      `This tool can help show how a change in income affects how much someone receives in public assistance from SNAP (Supplemental Nutrition Assistance Program) and Section 8 Housing Voucher benefits. It was designed for the case managers at `,
      { name: `__projectHope__` },
      ` with the aim of helping to predict changes in their clients' benefits.`,
    ],

    whyHeader: `Why is this tool important?`,
    why1:      `A cliff effect occurs when a slight change in a household’s circumstances - say, a slight pay raise - disproportionately lowers their benefits. The household is working to increase what they earn, but they end up with a net loss that actually puts them further behind. These cliff effects prevent many families from actually getting off of public assistance programs.`,
    why2:      `Cliff effects are also difficult to predict. The interactions between income, household s impact each other in unexpected ways. We're exploring ways to deal with this issue of complexity and help families better understand and predict their situation.`,

    videoLinkText:    `Two-minute video describing cliff effects`,
    quantLinkText:    `Quantitative scenarios demonstrating cliff effects`,
    benefitsLinkText: `Breakdown of different benefits offered in MA`,

    howToUseHeader: `How do I use this tool?`,
    howToUse:       `Go step-by-step to add information about a client's current benefits, household, income, and other relevant information. This information will be used to predict the client's approximate benefit amount. When you reach the end, change the 'Future Income' amount to see how a change in earned income will cause a change in benefit amount. Currently, the SNAP and Section 8 Housing Voucher programs are both available. Note that predictions may not directly match up with a client’s current benefit amount. The app’s focus is the amount of change that occurs in benefits when there are changes in earned income.`,
    howToUseNote:   [
      `Please note that this app does not store user data, so `,
      {
        name: `__refreshWarning__`,
        text: `if you refresh the page the data you've entered will be lost.`,
      },
      ` Each time you go through the app, it's a clean slate.`,
    ],

    whoMadeThisHeader: `Who is behind this?`,
    whoMadeThis1:      [
      `This application is part of a project made possible by a Boston Foundation Open Door Grant to the University of Massachusetts Boston's `,
      { name: `__centerForSocialPolicy__` },
      `, in close partnership with `,
      { name: `__projectHope__` },
      ` and `,
      { name: `__codeForBoston__` },
      `. The Center for Social Policy is the lead partner for the `,
      { name: `__onSolidGroundCoalition__` },
      `.`,
    ],
    whoMadeThis2: [
      `The code base is being maintained on `,
      { name: `__github__` },
      ` by `,
      { name: `__codeForBoston__` },
      ` volunteers. For more information or to report a bug, please contact `,
      { name: `__contactEmail__` },
      `.`,
    ],
    whoMadeThis3: [
      `Here's a special thank you to all the Code for Boston volunteers who brought you this application, especially `,
      { name: `__namesExceptLast__` },
      `, and `,
      { name: `__lastName__` },
      `.`,
    ],
  },

  visitPage: {
    'previous_v1.0':  `Previous`,
    'next_v1.0':      `Next`,
    'newClient_v1.0': `New Client`,

    stepBar: {
      currentBenefits: `Current Benefits`,
      household:       `Household`,
      currentIncome:   `Income`,
      currentExpenses: `Expenses`,
      predictions:     `Predictions`,
    },

    formHelpers: {
      weekly:   `Weekly`,
      monthly:  `Monthly`,
      yearly:   `Yearly`,
      yesLabel: `Yes`,
      noLabel:  `No`,
    },

    currentBenefits: {
      currentBenefits: `Current Benefits`,
      selectBenefits:  `Select the benefits you currently receive`,
      hasSection8:     {
        label: `Do you have Section 8 Housing?`,
        hint:  `Section 8 provides rental housing assistance.`,
      },
      hasSnap: {
        label: `Do you have SNAP?`,
        hint:  `SNAP provides assistance with buying food`,
      },
      next: `Next`,
    },

    household: {
      title:           `Household`,
      clarifier:       `Information about the members of your household.`,
      role:            `Role`,
      age:             `Age`,
      disabled:        `Disabled`,
      headOfHousehold: `Head of Household`,
      addMember:       `Add a member`,
      spouse:          `Spouse of Head of Household`,
      childOther:      `Child/Other Household Member`,
      previous:        `Previous`,
      next:            `Next`,
    },

    currentIncome: {
      title:                  `Current Household Income`,
      clarifier:              `Income that you collected in the past 12 months.`,
      explainSnapCalculation: `This prototype will attempt to make its own calculations for SNAP amount`,
      earnedIncome:           {
        label: `Earned income`,
        hint:  `Earned income is how much you and your family get paid from working`,
      },
      TAFDC: {
        label: `TAFDC`,
        hint:  `Transitional Aid to Families with Dependent Children provides short-term financial assistance to families with children`,
      },
      SSI: {
        label: `SSI`,
        hint:  `Supplemental Security Income is a federal program that provides financial and health care assistance to people 65 and over, or people who are blind or disabled`,
      },
      SSDI: {
        label: `SSDI`,
        hint:  `Social Security Disability Income is a federal program to help people with disabilities`,
      },
      childSupport: {
        label: `Child support recieved`,
        hint:  `Child support is money paid to you by a former spouse to help your child`,
      },
      unemployment: {
        label: `Unemployment`,
        hint:  `Unemployment benefits provide income to people who have been laid off`,
      },
      workersComp: {
        label: `Worker's compensation`,
        hint:  `Worker's Compensation provides assistance for people who have been injured on the job`,
      },
      pension: {
        label: `Pension`,
        hint:  `A pension provides income to retirees, usually from their former employers`,
      },
      socialSecurity: {
        label: `Social security`,
        hint:  `Social Security is a federal program that provides assistance to retirees`,
      },
      alimony: {
        label: `Alimony`,
        hint:  `Alimony is money paid by one spouse to the other after a divorce`,
      },
      otherIncome: {
        label: `Other income`,
        hint:  `Please note income you may have from sources that are not listed above`,
      },
      previous: `Previous`,
      next:     `Next`,
    },

    currentExpenses: {
      title:                           `Current Household Expenses`,
      unreimbursedNonMedicalChildCare: {
        sectionHeading:    `Reasonable Unreimbursed Non-Medical Child(ren) Care`,
        subheading:        `A "child" is a person 12 or younger. Don't include amounts that are paid for by other benefit programs.`,
        columnExpenseType: `Expense`,
        childDirectCare:   {
          label: `Direct care costs`,
          hint:  `How much do you pay for child care out of pocket?`,
        },
        childBeforeAndAfterSchoolCare: {
          label: `Before- and after-school care`,
          hint:  `How much do you pay for child care for times before or after school?`,
        },
        childTransportation: {
          label: `Transportation costs`,
          hint:  `How much do you pay for transportation?`,
        },
        childOtherCare: {
          label: `Other care`,
          hint:  `How much do you pay for other child care?`,
        },
        doEarnBecauseOfChildCare: `Does child care allow you to make additional income?`,
        earnedBecauseOfChildCare: `Income made possible by childcare expenses`,
      },
      childSupport: {
        sectionHeading:      `Child Support`,
        columnExpenseType:   `Expense`,
        childSupportPaidOut: {
          legallyObligated: `Legally obligated`,
          childSupport:     ` child support`,
        },
      },
      housing: {
        sectionHeading:      `Housing`,
        monthlyContractRent: {
          label: `Monthly Contract Rent (the total rent for your apartment)`,
          hint:  `The total rent for your apartment`,
        },
        monthlyRentShare: {
          label: `Your Monthly Rent Share (how much of the total rent you have to pay)`,
          hint:  `How much of the total rent you have to pay`,
        },
        utilitiesSubheading: `Which of these utilities do you pay for?`,
        climateControl:      {
          label: `Heating or cooling (e.g. A/C during summer)`,
          hint:  `How much do you pay if you have a separate bill for heating and/or cooling`,
        },
        nonHeatElectricity: {
          label: `Electricity for non-heating purposes`,
          hint:  `How much do you pay for any electric usage (other than for heat)`,
        },
        phone: {
          label: `Telephone service`,
          hint:  `How much do you pay for basic telephone service`,
        },
        fuelAssistance: {
          labelText: `Do you get Fuel Assistance?`,
          hint:      `Fuel Assistance helps you pay for heating fuel`,
        },
      },
      previous: `Previous`,
      next:     `Next`,
    },

    predictions: {},
  },
};
<commit_msg>Fix 'PROTOTYPE' typo<commit_after>export default {

  langName: `English`,
  langCode: `en`,

  header: {},

  footer: {
    header:    `Cliff Effects Tool`,
    cfbCredit: [
      `Made with `,
      { name: `__heartIcon__` },
      ` by Code for Boston`,
    ],
  },

  homePage: {
    appName:          `Cliff Effects Tool`,
    prototypeNote:    `GUIDANCE PROTOTYPE*`,
    cautionaryNote:   `*This is a prototype and should not be used to make financial decisions`,
    toFirstInputPage: `Get Started`,
    toAboutPage:      `Learn More`,
  },

  aboutPage: {
    aboutPageHeader: `About the Cliff Effects Tool`,

    whatForHeader:        `What is this tool for?`,
    whatForImportantNote: [
      {
        name: `__importantNote__`,
        text: `Important Note:`,
      },
      `This application is a minimum viable product. It should not be used as the sole tool to understand a client's SNAP or Section 8 financial situation, or for any other public assistance program.`,
    ],
    whatFor: [
      `This tool can help show how a change in income affects how much someone receives in public assistance from SNAP (Supplemental Nutrition Assistance Program) and Section 8 Housing Voucher benefits. It was designed for the case managers at `,
      { name: `__projectHope__` },
      ` with the aim of helping to predict changes in their clients' benefits.`,
    ],

    whyHeader: `Why is this tool important?`,
    why1:      `A cliff effect occurs when a slight change in a household’s circumstances - say, a slight pay raise - disproportionately lowers their benefits. The household is working to increase what they earn, but they end up with a net loss that actually puts them further behind. These cliff effects prevent many families from actually getting off of public assistance programs.`,
    why2:      `Cliff effects are also difficult to predict. The interactions between income, household s impact each other in unexpected ways. We're exploring ways to deal with this issue of complexity and help families better understand and predict their situation.`,

    videoLinkText:    `Two-minute video describing cliff effects`,
    quantLinkText:    `Quantitative scenarios demonstrating cliff effects`,
    benefitsLinkText: `Breakdown of different benefits offered in MA`,

    howToUseHeader: `How do I use this tool?`,
    howToUse:       `Go step-by-step to add information about a client's current benefits, household, income, and other relevant information. This information will be used to predict the client's approximate benefit amount. When you reach the end, change the 'Future Income' amount to see how a change in earned income will cause a change in benefit amount. Currently, the SNAP and Section 8 Housing Voucher programs are both available. Note that predictions may not directly match up with a client’s current benefit amount. The app’s focus is the amount of change that occurs in benefits when there are changes in earned income.`,
    howToUseNote:   [
      `Please note that this app does not store user data, so `,
      {
        name: `__refreshWarning__`,
        text: `if you refresh the page the data you've entered will be lost.`,
      },
      ` Each time you go through the app, it's a clean slate.`,
    ],

    whoMadeThisHeader: `Who is behind this?`,
    whoMadeThis1:      [
      `This application is part of a project made possible by a Boston Foundation Open Door Grant to the University of Massachusetts Boston's `,
      { name: `__centerForSocialPolicy__` },
      `, in close partnership with `,
      { name: `__projectHope__` },
      ` and `,
      { name: `__codeForBoston__` },
      `. The Center for Social Policy is the lead partner for the `,
      { name: `__onSolidGroundCoalition__` },
      `.`,
    ],
    whoMadeThis2: [
      `The code base is being maintained on `,
      { name: `__github__` },
      ` by `,
      { name: `__codeForBoston__` },
      ` volunteers. For more information or to report a bug, please contact `,
      { name: `__contactEmail__` },
      `.`,
    ],
    whoMadeThis3: [
      `Here's a special thank you to all the Code for Boston volunteers who brought you this application, especially `,
      { name: `__namesExceptLast__` },
      `, and `,
      { name: `__lastName__` },
      `.`,
    ],
  },

  visitPage: {
    'previous_v1.0':  `Previous`,
    'next_v1.0':      `Next`,
    'newClient_v1.0': `New Client`,

    stepBar: {
      currentBenefits: `Current Benefits`,
      household:       `Household`,
      currentIncome:   `Income`,
      currentExpenses: `Expenses`,
      predictions:     `Predictions`,
    },

    formHelpers: {
      weekly:   `Weekly`,
      monthly:  `Monthly`,
      yearly:   `Yearly`,
      yesLabel: `Yes`,
      noLabel:  `No`,
    },

    currentBenefits: {
      currentBenefits: `Current Benefits`,
      selectBenefits:  `Select the benefits you currently receive`,
      hasSection8:     {
        label: `Do you have Section 8 Housing?`,
        hint:  `Section 8 provides rental housing assistance.`,
      },
      hasSnap: {
        label: `Do you have SNAP?`,
        hint:  `SNAP provides assistance with buying food`,
      },
      next: `Next`,
    },

    household: {
      title:           `Household`,
      clarifier:       `Information about the members of your household.`,
      role:            `Role`,
      age:             `Age`,
      disabled:        `Disabled`,
      headOfHousehold: `Head of Household`,
      addMember:       `Add a member`,
      spouse:          `Spouse of Head of Household`,
      childOther:      `Child/Other Household Member`,
      previous:        `Previous`,
      next:            `Next`,
    },

    currentIncome: {
      title:                  `Current Household Income`,
      clarifier:              `Income that you collected in the past 12 months.`,
      explainSnapCalculation: `This prototype will attempt to make its own calculations for SNAP amount`,
      earnedIncome:           {
        label: `Earned income`,
        hint:  `Earned income is how much you and your family get paid from working`,
      },
      TAFDC: {
        label: `TAFDC`,
        hint:  `Transitional Aid to Families with Dependent Children provides short-term financial assistance to families with children`,
      },
      SSI: {
        label: `SSI`,
        hint:  `Supplemental Security Income is a federal program that provides financial and health care assistance to people 65 and over, or people who are blind or disabled`,
      },
      SSDI: {
        label: `SSDI`,
        hint:  `Social Security Disability Income is a federal program to help people with disabilities`,
      },
      childSupport: {
        label: `Child support recieved`,
        hint:  `Child support is money paid to you by a former spouse to help your child`,
      },
      unemployment: {
        label: `Unemployment`,
        hint:  `Unemployment benefits provide income to people who have been laid off`,
      },
      workersComp: {
        label: `Worker's compensation`,
        hint:  `Worker's Compensation provides assistance for people who have been injured on the job`,
      },
      pension: {
        label: `Pension`,
        hint:  `A pension provides income to retirees, usually from their former employers`,
      },
      socialSecurity: {
        label: `Social security`,
        hint:  `Social Security is a federal program that provides assistance to retirees`,
      },
      alimony: {
        label: `Alimony`,
        hint:  `Alimony is money paid by one spouse to the other after a divorce`,
      },
      otherIncome: {
        label: `Other income`,
        hint:  `Please note income you may have from sources that are not listed above`,
      },
      previous: `Previous`,
      next:     `Next`,
    },

    currentExpenses: {
      title:                           `Current Household Expenses`,
      unreimbursedNonMedicalChildCare: {
        sectionHeading:    `Reasonable Unreimbursed Non-Medical Child(ren) Care`,
        subheading:        `A "child" is a person 12 or younger. Don't include amounts that are paid for by other benefit programs.`,
        columnExpenseType: `Expense`,
        childDirectCare:   {
          label: `Direct care costs`,
          hint:  `How much do you pay for child care out of pocket?`,
        },
        childBeforeAndAfterSchoolCare: {
          label: `Before- and after-school care`,
          hint:  `How much do you pay for child care for times before or after school?`,
        },
        childTransportation: {
          label: `Transportation costs`,
          hint:  `How much do you pay for transportation?`,
        },
        childOtherCare: {
          label: `Other care`,
          hint:  `How much do you pay for other child care?`,
        },
        doEarnBecauseOfChildCare: `Does child care allow you to make additional income?`,
        earnedBecauseOfChildCare: `Income made possible by childcare expenses`,
      },
      childSupport: {
        sectionHeading:      `Child Support`,
        columnExpenseType:   `Expense`,
        childSupportPaidOut: {
          legallyObligated: `Legally obligated`,
          childSupport:     ` child support`,
        },
      },
      housing: {
        sectionHeading:      `Housing`,
        monthlyContractRent: {
          label: `Monthly Contract Rent (the total rent for your apartment)`,
          hint:  `The total rent for your apartment`,
        },
        monthlyRentShare: {
          label: `Your Monthly Rent Share (how much of the total rent you have to pay)`,
          hint:  `How much of the total rent you have to pay`,
        },
        utilitiesSubheading: `Which of these utilities do you pay for?`,
        climateControl:      {
          label: `Heating or cooling (e.g. A/C during summer)`,
          hint:  `How much do you pay if you have a separate bill for heating and/or cooling`,
        },
        nonHeatElectricity: {
          label: `Electricity for non-heating purposes`,
          hint:  `How much do you pay for any electric usage (other than for heat)`,
        },
        phone: {
          label: `Telephone service`,
          hint:  `How much do you pay for basic telephone service`,
        },
        fuelAssistance: {
          labelText: `Do you get Fuel Assistance?`,
          hint:      `Fuel Assistance helps you pay for heating fuel`,
        },
      },
      previous: `Previous`,
      next:     `Next`,
    },

    predictions: {},
  },
};
<|endoftext|>


<commit_before>/**
 * @author Diego Alberto Molina Vera
 * @copyright 2016 - 2018
 */

const {
    // workspace,
    commands,
    window
} = require('vscode');
const assert = require('assert');
const sinon = require('sinon');

// -================= // =================-
const {
    Converter,
    TEST_cleanUnits
} = require('./../converter');
const units = require('./../helpers/units');
const {
    PLACE_HOLDER_INPUT,
    PLACE_HOLDER_PROMPT
} = require('./../constants/strings');

// -================= // =================-
const getQuickPick = () =>
    window.showQuickPick(units, {
        matchOnDescription: true,
        placeHolder: PLACE_HOLDER_INPUT
    });

const getInputBox = () =>
    window.showInputBox({
        prompt: PLACE_HOLDER_PROMPT,
        value: ''
    });

const getUnitAt = position => {
    const { label, description } = units[position];

    return {
        label,
        description
    };
};

const isNotTextSelected = () => {
    const { selections } = window.activeTextEditor;
    const { start, end } = selections[0];

    return start.line === end.line || start.character === end.character;
};

// -================= // =================-

describe('Extension Tests', () => {

    it('Executes the commmand extension', done => {
        commands.executeCommand('extension.unitConverter')
            .then(() => {
                assert(true);
                done();
            }, () => {
                done();
            });
    });

    describe('Input prompt actions', () => {
        it('Selects `px` from the input prompt and add a value to convert', done => {
            if (isNotTextSelected()) {
                const showQuickPick = sinon.stub(window, 'showQuickPick');
                const showInputBox = sinon.stub(window, 'showInputBox');

                showQuickPick.resolves(getUnitAt(0));
                const quickPick = getQuickPick();

                showInputBox.resolves('19px');
                const inputBox = getInputBox();

                Promise.all([quickPick, inputBox])
                    .then(resolve => {
                        [pick, input] = resolve;

                        assert(pick.label === 'px');
                        assert(pick.description === 'Pixels');
                        assert(showQuickPick.calledOnce);
                        showQuickPick.restore();

                        assert(input === '19px');
                        assert(showInputBox.calledOnce);
                        showInputBox.restore();

                        const result = Converter.convert(TEST_cleanUnits(input), pick.label);
                        assert(result === '1.188em');
                        done();
                    });
            }
        });

        it('Selects `em|rem` from the input prompt and add a value', done => {
            if (isNotTextSelected()) {
                const showQuickPick = sinon.stub(window, 'showQuickPick');
                const showInputBox = sinon.stub(window, 'showInputBox');

                showQuickPick.resolves(getUnitAt(1));
                const quickPick = getQuickPick();

                showInputBox.resolves('1.188em');
                const inputBox = getInputBox();

                Promise.all([quickPick, inputBox])
                    .then(resolve => {
                        [pick, input] = resolve;

                        assert(pick.label === '[em|rem]');
                        assert(pick.description === 'M');
                        assert(showQuickPick.calledOnce);
                        showQuickPick.restore();

                        assert(input === '1.188em');
                        assert(showInputBox.calledOnce);
                        showInputBox.restore();

                        const result = Converter.convert(
                            TEST_cleanUnits(input), pick.label === '[em|rem]' && 'em'
                        );
                        assert(result === '19px');
                        done();
                    });
            }
        });

        it('Selects `#` from the input prompt and add a value', done => {
            if (isNotTextSelected()) {
                const showQuickPick = sinon.stub(window, 'showQuickPick');
                const showInputBox = sinon.stub(window, 'showInputBox');

                showQuickPick.resolves(getUnitAt(2));
                const quickPick = getQuickPick();

                showInputBox.resolves('#f1f1f1');
                const inputBox = getInputBox();

                Promise.all([quickPick, inputBox])
                    .then(resolve => {
                        [pick, input] = resolve;

                        assert(pick.label === '#');
                        assert(pick.description === 'Hexadecimal');
                        assert(showQuickPick.calledOnce);
                        showQuickPick.restore();

                        assert(input === '#f1f1f1');
                        assert(showInputBox.calledOnce);
                        showInputBox.restore();

                        const result = Converter.convert(
                            TEST_cleanUnits(input), pick.label
                        );
                        assert(result === 'rgba(241, 241, 241, 1) | rgb(241, 241, 241)');
                        done();
                    });
            }
        });

        it('Selects `rgb` from the input prompt', done => {
            if (isNotTextSelected()) {
                const showQuickPick = sinon.stub(window, 'showQuickPick');
                const showInputBox = sinon.stub(window, 'showInputBox');

                showQuickPick.resolves(getUnitAt(3));
                const quickPick = getQuickPick();

                showInputBox.resolves('rgb(137, 94, 173)');
                const inputBox = getInputBox();

                Promise.all([quickPick, inputBox])
                    .then(resolve => {
                        [pick, input] = resolve;

                        assert(pick.label === 'rgb');
                        assert(pick.description === 'Red Green Blue');
                        assert(showQuickPick.calledOnce);
                        showQuickPick.restore();

                        assert(input === 'rgb(137, 94, 173)');
                        assert(showInputBox.calledOnce);
                        showInputBox.restore();

                        const result = Converter.convert(
                            TEST_cleanUnits(input), pick.label
                        );
                        assert(result === '#895ead');
                        done();
                    });
            }
        });

        it('Selects `rgba` from the input prompt', done => {
            if (isNotTextSelected()) {
                const showQuickPick = sinon.stub(window, 'showQuickPick');
                const showInputBox = sinon.stub(window, 'showInputBox');

                showQuickPick.resolves(getUnitAt(4));
                const quickPick = getQuickPick();

                showInputBox.resolves('rgb(137, 94, 173, 1)');
                const inputBox = getInputBox();

                Promise.all([quickPick, inputBox])
                    .then(resolve => {
                        [pick, input] = resolve;

                        assert(pick.label === 'rgba');
                        assert(pick.description === 'Red Green Blue Alpha');
                        assert(showQuickPick.calledOnce);
                        showQuickPick.restore();

                        assert(input === 'rgb(137, 94, 173, 1)');
                        assert(showInputBox.calledOnce);
                        showInputBox.restore();

                        const result = Converter.convert(
                            TEST_cleanUnits(input), pick.label
                        );
                        assert(result === '#895ead');
                        done();
                    });
            }
        });

        it('Selects `color` from the input prompt', done => {
            if (isNotTextSelected()) {
                const showQuickPick = sinon.stub(window, 'showQuickPick');
                const showInputBox = sinon.stub(window, 'showInputBox');

                showQuickPick.resolves(getUnitAt(5));
                const quickPick = getQuickPick();

                showInputBox.resolves('white');
                const inputBox = getInputBox();

                Promise.all([quickPick, inputBox])
                    .then(resolve => {
                        [pick, input] = resolve;

                        assert(pick.label === 'color');
                        assert(pick.description === 'Color value (e.g. white)');
                        assert(showQuickPick.calledOnce);
                        showQuickPick.restore();

                        assert(input === 'white');
                        assert(showInputBox.calledOnce);
                        showInputBox.restore();
                        const result = Converter.convert(input, pick.label);
                        assert(result === '#fff');
                        done();
                    });
            }
        });

    });
});
<commit_msg>fixed destructuring array declaration<commit_after>/**
 * @author Diego Alberto Molina Vera
 * @copyright 2016 - 2018
 */

const {
    // workspace,
    commands,
    window
} = require('vscode');
const assert = require('assert');
const sinon = require('sinon');

// -================= // =================-
const {
    Converter,
    TEST_cleanUnits
} = require('./../converter');
const units = require('./../helpers/units');
const {
    PLACE_HOLDER_INPUT,
    PLACE_HOLDER_PROMPT
} = require('./../constants/strings');

// -================= // =================-
const getQuickPick = () =>
    window.showQuickPick(units, {
        matchOnDescription: true,
        placeHolder: PLACE_HOLDER_INPUT
    });

const getInputBox = () =>
    window.showInputBox({
        prompt: PLACE_HOLDER_PROMPT,
        value: ''
    });

const getUnitAt = position => {
    const { label, description } = units[position];

    return {
        label,
        description
    };
};

const isNotTextSelected = () => {
    const { selections } = window.activeTextEditor;
    const { start, end } = selections[0];

    return start.line === end.line || start.character === end.character;
};

// -================= // =================-

describe('Extension Tests', () => {
    it('Executes the commmand extension', done => {
        commands.executeCommand('extension.unitConverter')
            .then(() => {
                assert(true);
                done();
            }, () => {
                done();
            });
    });

    describe('Input prompt actions', () => {
        it('Selects `px` from the input prompt and add a value to convert', done => {
            if (isNotTextSelected()) {
                const showQuickPick = sinon.stub(window, 'showQuickPick');
                const showInputBox = sinon.stub(window, 'showInputBox');

                showQuickPick.resolves(getUnitAt(0));
                const quickPick = getQuickPick();

                showInputBox.resolves('19px');
                const inputBox = getInputBox();

                Promise.all([quickPick, inputBox])
                    .then(resolve => {
                        const [pick, input] = resolve;

                        assert(pick.label === 'px');
                        assert(pick.description === 'Pixels');
                        assert(showQuickPick.calledOnce);
                        showQuickPick.restore();

                        assert(input === '19px');
                        assert(showInputBox.calledOnce);
                        showInputBox.restore();

                        const result = Converter.convert(TEST_cleanUnits(input), pick.label);
                        assert(result === '1.188em');
                        done();
                    });
            }
        });

        it('Selects `em|rem` from the input prompt and add a value', done => {
            if (isNotTextSelected()) {
                const showQuickPick = sinon.stub(window, 'showQuickPick');
                const showInputBox = sinon.stub(window, 'showInputBox');

                showQuickPick.resolves(getUnitAt(1));
                const quickPick = getQuickPick();

                showInputBox.resolves('1.188em');
                const inputBox = getInputBox();

                Promise.all([quickPick, inputBox])
                    .then(resolve => {
                        const [pick, input] = resolve;

                        assert(pick.label === '[em|rem]');
                        assert(pick.description === 'M');
                        assert(showQuickPick.calledOnce);
                        showQuickPick.restore();

                        assert(input === '1.188em');
                        assert(showInputBox.calledOnce);
                        showInputBox.restore();

                        const result = Converter.convert(
                            TEST_cleanUnits(input), pick.label === '[em|rem]' && 'em'
                        );
                        assert(result === '19px');
                        done();
                    });
            }
        });

        it('Selects `#` from the input prompt and add a value', done => {
            if (isNotTextSelected()) {
                const showQuickPick = sinon.stub(window, 'showQuickPick');
                const showInputBox = sinon.stub(window, 'showInputBox');

                showQuickPick.resolves(getUnitAt(2));
                const quickPick = getQuickPick();

                showInputBox.resolves('#f1f1f1');
                const inputBox = getInputBox();

                Promise.all([quickPick, inputBox])
                    .then(resolve => {
                        const [pick, input] = resolve;

                        assert(pick.label === '#');
                        assert(pick.description === 'Hexadecimal');
                        assert(showQuickPick.calledOnce);
                        showQuickPick.restore();

                        assert(input === '#f1f1f1');
                        assert(showInputBox.calledOnce);
                        showInputBox.restore();

                        const result = Converter.convert(
                            TEST_cleanUnits(input), pick.label
                        );
                        assert(result === 'rgba(241, 241, 241, 1) | rgb(241, 241, 241)');
                        done();
                    });
            }
        });

        it('Selects `rgb` from the input prompt', done => {
            if (isNotTextSelected()) {
                const showQuickPick = sinon.stub(window, 'showQuickPick');
                const showInputBox = sinon.stub(window, 'showInputBox');

                showQuickPick.resolves(getUnitAt(3));
                const quickPick = getQuickPick();

                showInputBox.resolves('rgb(137, 94, 173)');
                const inputBox = getInputBox();

                Promise.all([quickPick, inputBox])
                    .then(resolve => {
                        const [pick, input] = resolve;

                        assert(pick.label === 'rgb');
                        assert(pick.description === 'Red Green Blue');
                        assert(showQuickPick.calledOnce);
                        showQuickPick.restore();

                        assert(input === 'rgb(137, 94, 173)');
                        assert(showInputBox.calledOnce);
                        showInputBox.restore();

                        const result = Converter.convert(
                            TEST_cleanUnits(input), pick.label
                        );
                        assert(result === '#895ead');
                        done();
                    });
            }
        });

        it('Selects `rgba` from the input prompt', done => {
            if (isNotTextSelected()) {
                const showQuickPick = sinon.stub(window, 'showQuickPick');
                const showInputBox = sinon.stub(window, 'showInputBox');

                showQuickPick.resolves(getUnitAt(4));
                const quickPick = getQuickPick();

                showInputBox.resolves('rgb(137, 94, 173, 1)');
                const inputBox = getInputBox();

                Promise.all([quickPick, inputBox])
                    .then(resolve => {
                        const [pick, input] = resolve;

                        assert(pick.label === 'rgba');
                        assert(pick.description === 'Red Green Blue Alpha');
                        assert(showQuickPick.calledOnce);
                        showQuickPick.restore();

                        assert(input === 'rgb(137, 94, 173, 1)');
                        assert(showInputBox.calledOnce);
                        showInputBox.restore();

                        const result = Converter.convert(
                            TEST_cleanUnits(input), pick.label
                        );
                        assert(result === '#895ead');
                        done();
                    });
            }
        });

        it('Selects `color` from the input prompt', done => {
            if (isNotTextSelected()) {
                const showQuickPick = sinon.stub(window, 'showQuickPick');
                const showInputBox = sinon.stub(window, 'showInputBox');

                showQuickPick.resolves(getUnitAt(5));
                const quickPick = getQuickPick();

                showInputBox.resolves('white');
                const inputBox = getInputBox();

                Promise.all([quickPick, inputBox])
                    .then(resolve => {
                        const [pick, input] = resolve;

                        assert(pick.label === 'color');
                        assert(pick.description === 'Color value (e.g. white)');
                        assert(showQuickPick.calledOnce);
                        showQuickPick.restore();

                        assert(input === 'white');
                        assert(showInputBox.calledOnce);
                        showInputBox.restore();
                        const result = Converter.convert(input, pick.label);
                        assert(result === '#fff');
                        done();
                    });
            }
        });
    });
});
<|endoftext|>


<commit_before>const LEVELS = {
  NOTHING: 0,
  ERROR: 1,
  WARN: 2,
  INFO: 4,
  DEBUG: 5,
}

const createLevel = (label, level, currentLevel, loggerFunction) => (message, extra = {}) => {
  if (level > currentLevel) return
  const logData = Object.assign(
    {
      level: label,
      timestamp: new Date().toISOString(),
      message,
    },
    extra
  )

  loggerFunction(JSON.stringify(logData))
}

const createLogger = ({ level = parseInt(process.env.LOG_LEVEL, 10) || LEVELS.INFO } = {}) => ({
  info: createLevel('INFO', LEVELS.INFO, level, console.info),
  error: createLevel('ERROR', LEVELS.ERROR, level, console.error),
  warn: createLevel('WARN', LEVELS.WARN, level, console.warn),
  debug: createLevel('DEBUG', LEVELS.DEBUG, level, console.log),
})

module.exports = {
  LEVELS,
  createLogger,
}
<commit_msg>Allow env variable LOG_LEVEL to override the log level<commit_after>const LEVELS = {
  NOTHING: 0,
  ERROR: 1,
  WARN: 2,
  INFO: 4,
  DEBUG: 5,
}

const createLevel = (label, level, currentLevel, loggerFunction) => (message, extra = {}) => {
  if (level > currentLevel) return
  const logData = Object.assign(
    {
      level: label,
      timestamp: new Date().toISOString(),
      message,
    },
    extra
  )

  loggerFunction(JSON.stringify(logData))
}

const createLogger = ({ level = LEVELS.INFO } = {}) => {
  const logLevel = parseInt(process.env.LOG_LEVEL, 10) || level
  return {
    info: createLevel('INFO', LEVELS.INFO, logLevel, console.info),
    error: createLevel('ERROR', LEVELS.ERROR, logLevel, console.error),
    warn: createLevel('WARN', LEVELS.WARN, logLevel, console.warn),
    debug: createLevel('DEBUG', LEVELS.DEBUG, logLevel, console.log),
  }
}

module.exports = {
  LEVELS,
  createLogger,
}
<|endoftext|>


<commit_before>var fs = require('fs');
var EmptyTpl = fs.readFileSync(__dirname + '/templates/empty-moves.html', 'utf8');
var LunchMoveTpl = fs.readFileSync(__dirname + '/templates/lunch-move.html', 'utf8');
var LunchMovesTpl = fs.readFileSync(__dirname + '/templates/lunch-moves.html', 'utf8')
var MoveFormTpl = fs.readFileSync(__dirname + '/templates/lunch-move-form.html', 'utf8');
var EmptyQueryTpl = fs.readFileSync(__dirname + '/templates/empty-query.html', 'utf8');
var Spot = require('app/entities').Spot;

var channel = Backbone.Radio.channel('global');

var LunchMoveView = Marionette.ItemView.extend({
    tagName: 'li',
    className: 'list-group-item',
    template: _.template(LunchMoveTpl),
    templateHelpers: {
        spotName: function(){
            console.log(this.spot);
            return channel.request('entities:spots').get(this.spot).get('name');
        }
    }
});

var EmptyView = Marionette.ItemView.extend({
    tagName: 'li',
    className: 'list-group-item',
    template: _.template(EmptyTpl)
});

var LunchMovesView = Marionette.CompositeView.extend({
    emptyView: EmptyView,
    childView: LunchMoveView,
    childViewContainer: 'ul',
    template: _.template(LunchMovesTpl)
});

var MoveFormView = Marionette.ItemView.extend({
    template: _.template(MoveFormTpl),
    ui: {
        'form': 'form',
        'spot': '[name="spot"]',
        'spotId': '[name="spot_id"]',
        'user': '[name="user"]'
    },
    events: {
        'typeahead:select @ui.spot': 'onTypeaheadSelect',
        'click [data-action="addSpot"]': 'addSpot',
        'change @ui.form': 'onFormChange',
        'blur @ui.spot': 'onSpotBlur',
        'keydown input': function(e){
            if (e.keyCode === 13) {
                e.preventDefault();
                $(e.currentTarget).blur();
            }
        }
    },
    addSpot: function(){
        var spot = new Spot({
            name: this.ui.spot.typeahead('val')
        });

        spot.save({}, {
            success: _.bind(function(){
                channel.request('entities:spots').add(spot);
                this.ui.spot.typeahead('val', spot.get('name')).blur();
            }, this)
        });
    },
    onShow: function(){
        var spots = new Bloodhound({
            datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
            queryTokenizer: Bloodhound.tokenizers.whitespace,
            local: channel.request('entities:spots').toJSON()
        });

        this.ui.spot.typeahead({
            hint: true,
            highlight: true,
            minLength: 1
        },
        {
            display: 'name',
            name: 'spots',
            source: spots,
            templates: {
                empty: _.template(EmptyQueryTpl)
            }
        });
    },
    onFormChange: function(){
        var spotId = this.ui.spotId.val();
        var user = this.ui.user.val();

        if (!!spotId && !!user) {
            this.model.save({
                spot: spotId,
                user: user
            }, {
                success: function(){
                    Backbone.history.navigate('/moves', {trigger: true});
                }
            });
        }
    },
    onSpotBlur: function(){
        var spots = channel.request('entities:spots');
        var spotId = this.ui.spotId.val();

        if (!spotId) {
            var spotVal = this.ui.spot.typeahead('val');
            var selectedSpot = spots.find(function(spot){
                return spot.get('name').toLowerCase() == spotVal.toLowerCase();
            });

            if (selectedSpot) {
                this.ui.spotId.val(selectedSpot.id).change();
                spotId = selectedSpot.id;
            }
        }

        this.ui.spot.typeahead('val', spotId ? spots.get(+spotId).get('name') : '');
    },
    onTypeaheadSelect: function(e, obj){
        this.ui.spotId.val(obj.id).change();
    },
    templateHelpers: function(){
        return {
            spots: channel.request('entities:spots').toJSON()
        }
    }
});

module.exports = {
    LunchMovesView: LunchMovesView,
    MoveFormView: MoveFormView
}
<commit_msg>limit saving<commit_after>var fs = require('fs');
var EmptyTpl = fs.readFileSync(__dirname + '/templates/empty-moves.html', 'utf8');
var LunchMoveTpl = fs.readFileSync(__dirname + '/templates/lunch-move.html', 'utf8');
var LunchMovesTpl = fs.readFileSync(__dirname + '/templates/lunch-moves.html', 'utf8')
var MoveFormTpl = fs.readFileSync(__dirname + '/templates/lunch-move-form.html', 'utf8');
var EmptyQueryTpl = fs.readFileSync(__dirname + '/templates/empty-query.html', 'utf8');
var Spot = require('app/entities').Spot;

var channel = Backbone.Radio.channel('global');

var LunchMoveView = Marionette.ItemView.extend({
    tagName: 'li',
    className: 'list-group-item',
    template: _.template(LunchMoveTpl),
    templateHelpers: {
        spotName: function(){
            console.log(this.spot);
            return channel.request('entities:spots').get(this.spot).get('name');
        }
    }
});

var EmptyView = Marionette.ItemView.extend({
    tagName: 'li',
    className: 'list-group-item',
    template: _.template(EmptyTpl)
});

var LunchMovesView = Marionette.CompositeView.extend({
    emptyView: EmptyView,
    childView: LunchMoveView,
    childViewContainer: 'ul',
    template: _.template(LunchMovesTpl)
});

var MoveFormView = Marionette.ItemView.extend({
    template: _.template(MoveFormTpl),
    ui: {
        'form': 'form',
        'spot': '[name="spot"]',
        'spotId': '[name="spot_id"]',
        'user': '[name="user"]'
    },
    events: {
        'typeahead:select @ui.spot': 'onTypeaheadSelect',
        'click [data-action="addSpot"]': 'addSpot',
        'change @ui.form': 'onFormChange',
        'blur @ui.spot': 'onSpotBlur',
        'keydown input': function(e){
            if (e.keyCode === 13) {
                e.preventDefault();
                $(e.currentTarget).blur();
            }
        }
    },
    addSpot: function(){
        var spot = new Spot({
            name: this.ui.spot.typeahead('val')
        });

        spot.save({}, {
            success: _.bind(function(){
                channel.request('entities:spots').add(spot);
                this.ui.spot.typeahead('val', spot.get('name')).blur();
            }, this)
        });
    },
    onShow: function(){
        var spots = new Bloodhound({
            datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
            queryTokenizer: Bloodhound.tokenizers.whitespace,
            local: channel.request('entities:spots').toJSON()
        });

        this.ui.spot.typeahead({
            hint: true,
            highlight: true,
            minLength: 1
        },
        {
            display: 'name',
            name: 'spots',
            source: spots,
            templates: {
                empty: _.template(EmptyQueryTpl)
            }
        });
    },
    onFormChange: function(){
        if (this._disableSaving) {
            return;
        }

        var spotId = this.ui.spotId.val();
        var user = this.ui.user.val();

        if (spotId && user) {
            this._disableSaving = true;

            this.model.save({
                spot: spotId,
                user: user
            }, {
                success: function(){
                    Backbone.history.navigate('/moves', {trigger: true});
                }
            });
        }
    },
    onSpotBlur: function(){
        var spots = channel.request('entities:spots');
        var spotId = this.ui.spotId.val();

        if (!spotId) {
            var spotVal = this.ui.spot.typeahead('val');
            var selectedSpot = spots.find(function(spot){
                return spot.get('name').toLowerCase() == spotVal.toLowerCase();
            });

            if (selectedSpot) {
                this.ui.spotId.val(selectedSpot.id).change();
                spotId = selectedSpot.id;
            }
        }

        this.ui.spot.typeahead('val', spotId ? spots.get(+spotId).get('name') : '');
    },
    onTypeaheadSelect: function(e, obj){
        this.ui.spotId.val(obj.id).change();
    },
    templateHelpers: function(){
        return {
            spots: channel.request('entities:spots').toJSON()
        }
    }
});

module.exports = {
    LunchMovesView: LunchMovesView,
    MoveFormView: MoveFormView
}
<|endoftext|>


<commit_before> /*!
 * jQuery PLugin Base v1.2
 * https://github.com/marcosfreitas/jquery-plugin-base/
 *
 * Copyright 2015, 2016 Marcos Freitas
 * Released under the MIT license
 */

;(function($) {
	'use strict'; // ecma script 5

	// the __function is a method or event's name
	$.fn.MyPlugin = function (__function, options) {

		/*! default properties */

		var __default = {
			'name' : 'marcos',
			'lastname' : 'freitas',
			'yearold' : 25
		},

		// merging new properties to default
		config = $.extend({}, __default, options),

		/*! private properties */

		priv = {
			'ajax' : {
				'interval_requests' : 3000,
				'method' : 'GET'
			}
		},

		/*! global vars */

		// a counter used on private.recursive
		recursive_cron = 0,
		// an object to store the values on global way like:  database.user = {name="marcos"}
		database = {},

		/*! private methods, they can't be calling from instances */
		privates = {

			// call the function recursively until the limit and turn to success or error of requests
			recursive : function (callback) {

				if (priv.ajax.interval_requests/1000 <= 15) {
					console.warn('waiting '+priv.ajax.interval_requests+' seconds...');
					recursive_cron =
						setInterval(function() {

							priv.ajax.interval_requests += 3000;
							clearInterval(recursive_cron);
							// call the function passed
							callback();

						}, priv.ajax.interval_requests)
					;
				} else {
					priv.ajax.interval_requests = 3000;
					clearInterval(recursive_cron);
					return false ;
				}

				return true;
			},

			// make all the ajax request and return a promise
			// jsonp_callback is optional, he define the cross-domain and o dataType as jsonp
			get : function (url, jsonp_callback) {

				try {

					var o = {};

					// request's parameters
					o.cache  = false;
					o.timeout = 10000;
					o.url    = url;
					o.method = priv.ajax.method;

					if (typeof jsonp_callback !== 'undefined') {
						o.crossDomain = true;
						o.jsonpCallback = jsonp_callback;
						o.dataType      = 'jsonp';
					} else {
						o.dataType = 'json';
					}
					return $.ajax(o);

				} catch (e) {
					console.error('I couldn\'t do this...');
				}
			},
		},

		methods = {

			init : function (url) {
				methods.fake(url);
			},

			b : function (param, param2) {
				console.log(param, param2);
			},

			/*! a example for a method what do a request to a api */
			fake : function(url) {

				if (typeof url === 'undefined') {
					url = 'http://www.mocky.io/v2/56969c1125000012061affbb';
				}

				var _fake = privates.get(url);

				// Promises running after _fake respond
				$.when(_fake).then(
					// the number of parameters to this function is in accord with number of variables (requests) previously defined like '_fake'
					// will receive a json
					function __resultado(json) {
						// here is the code executed on .done() of $.ajax()
						if (typeof json === 'object') {

							console.info(json);
							events.onLoad();

						} else {
							// calling recursively, after many attempts trigger a error
							if (!privates.recursive(methods.fake)) {
								$.error('The request has been failed')
							}
						}

						// here put what you need to now...

					},
					// trigger error because the request has been failed
					function __erro(e) {
						$.error(e);
					}
				);
			}
		},

		events = {
			// you can organizze this like you want
			onClick: function() {},
			onHover: function() {},
			onLoad: function() { console.log('this don\'t represent the "on load" of the browser, but the load after any task what you has been defined, like a ajax request...') }
		};

		/*! Modify this only if you understand, be careful */
	   // call the methods or events
	   var arr_options = Array();

	    if (typeof options !== 'undefined') {
	    	try {
			// Array.prototype.slice não funciona até o IE 8 e no chrome 14
		        // http://stackoverflow.com/questions/7056925/how-does-array-prototype-slice-call-work
		        // se não for um array ele vai separar a string em letras
		        // para passar corretamente parâmetros para os métodos ou funçõesé preciso que opções seja um array,
		        // ou um array-like (um objeto com índices numéricos e uma propriedade 'length')
		        // repassa todos os elementos do array, mas depende de quantos a função está esperando receber
		        arr_options = Array.prototype.slice.call(opcoes, 0);
		} catch(err){
		        // slow but works on IE
		            arr_options = [];
		        var length = options.length;
		        for(var o=0; o < length; o++){
		            arr_options.push(options[o]);
		        }
		    }
	    }

	    // the functions at methods and events can be "returned" calling methods['onload'] by example
	    if ( methods[__function] ) {
		// the apply() method call the function with a value (this) and arguments provided like an array (or a object "array-like").
		return methods[__function].apply( this, arr_options);
	    }
	    else if ( events[__function] ) {
	    	return events[__function].apply( this, arr_options);
	    }
	    // don't found anything, method or event, with that name (__func)
	    // so call the init method passing the options if this is a object
	    else if ( typeof options === 'object' ) {
	    	return methods.init.apply( this, options );
	    }
	    // finaly call the method init passing the selector object jquery or not
	    else if ( typeof __function === 'undefined' && typeof options === 'undefined' ) {
	    	 // if only the plugin is for the type $.fn
	    	 return methods.init(this);
	    	 //return methods.init();
	    }
	    else {
	    	$.error( 'The method or event "' +  __func + '" don not exists on MyPLugin.js' );
	    }

	};

})(jQuery);
<commit_msg>removed the call to the method fake from init<commit_after> /*!
 * jQuery PLugin Base v1.2
 * https://github.com/marcosfreitas/jquery-plugin-base/
 *
 * Copyright 2015, 2016 Marcos Freitas
 * Released under the MIT license
 */

;(function($) {
	'use strict'; // ecma script 5

	// the __function is a method or event's name
	$.fn.MyPlugin = function (__function, options) {

		/*! default properties */

		var __default = {
			'name' : 'marcos',
			'lastname' : 'freitas',
			'yearold' : 25
		},

		// merging new properties to default
		config = $.extend({}, __default, options),

		/*! private properties */

		priv = {
			'ajax' : {
				'interval_requests' : 3000,
				'method' : 'GET'
			}
		},

		/*! global vars */

		// a counter used on private.recursive
		recursive_cron = 0,
		// an object to store the values on global way like:  database.user = {name="marcos"}
		database = {},

		/*! private methods, they can't be calling from instances */
		privates = {

			// call the function recursively until the limit and turn to success or error of requests
			recursive : function (callback) {

				if (priv.ajax.interval_requests/1000 <= 15) {
					console.warn('waiting '+priv.ajax.interval_requests+' seconds...');
					recursive_cron =
						setInterval(function() {

							priv.ajax.interval_requests += 3000;
							clearInterval(recursive_cron);
							// call the function passed
							callback();

						}, priv.ajax.interval_requests)
					;
				} else {
					priv.ajax.interval_requests = 3000;
					clearInterval(recursive_cron);
					return false ;
				}

				return true;
			},

			// make all the ajax request and return a promise
			// jsonp_callback is optional, he define the cross-domain and o dataType as jsonp
			get : function (url, jsonp_callback) {

				try {

					var o = {};

					// request's parameters
					o.cache  = false;
					o.timeout = 10000;
					o.url    = url;
					o.method = priv.ajax.method;

					if (typeof jsonp_callback !== 'undefined') {
						o.crossDomain = true;
						o.jsonpCallback = jsonp_callback;
						o.dataType      = 'jsonp';
					} else {
						o.dataType = 'json';
					}
					return $.ajax(o);

				} catch (e) {
					console.error('I couldn\'t do this...');
				}
			},
		},

		methods = {

			init : function (param) {
				console.log(param);
			},

			b : function (param, param2) {
				console.log(param, param2);
			},

			/*! a example for a method what do a request to a api */
			fake : function(url) {

				if (typeof url === 'undefined') {
					url = 'http://www.mocky.io/v2/56969c1125000012061affbb';
				}

				var _fake = privates.get(url);

				// Promises running after _fake respond
				$.when(_fake).then(
					// the number of parameters to this function is in accord with number of variables (requests) previously defined like '_fake'
					// will receive a json
					function __resultado(json) {
						// here is the code executed on .done() of $.ajax()
						if (typeof json === 'object') {

							console.info(json);
							events.onLoad();

						} else {
							// calling recursively, after many attempts trigger a error
							if (!privates.recursive(methods.fake)) {
								$.error('The request has been failed')
							}
						}

						// here put what you need to now...

					},
					// trigger error because the request has been failed
					function __erro(e) {
						$.error(e);
					}
				);
			}
		},

		events = {
			// you can organizze this like you want
			onClick: function() {},
			onHover: function() {},
			onLoad: function() { console.log('this don\'t represent the "on load" of the browser, but the load after any task what you has been defined, like a ajax request...') }
		};

		/*! Modify this only if you understand, be careful */
	   // call the methods or events
	   var arr_options = Array();

	    if (typeof options !== 'undefined') {
	    	try {
			// Array.prototype.slice não funciona até o IE 8 e no chrome 14
		        // http://stackoverflow.com/questions/7056925/how-does-array-prototype-slice-call-work
		        // se não for um array ele vai separar a string em letras
		        // para passar corretamente parâmetros para os métodos ou funçõesé preciso que opções seja um array,
		        // ou um array-like (um objeto com índices numéricos e uma propriedade 'length')
		        // repassa todos os elementos do array, mas depende de quantos a função está esperando receber
		        arr_options = Array.prototype.slice.call(opcoes, 0);
		} catch(err){
		        // slow but works on IE
		            arr_options = [];
		        var length = options.length;
		        for(var o=0; o < length; o++){
		            arr_options.push(options[o]);
		        }
		    }
	    }

	    // the functions at methods and events can be "returned" calling methods['onload'] by example
	    if ( methods[__function] ) {
		// the apply() method call the function with a value (this) and arguments provided like an array (or a object "array-like").
		return methods[__function].apply( this, arr_options);
	    }
	    else if ( events[__function] ) {
	    	return events[__function].apply( this, arr_options);
	    }
	    // don't found anything, method or event, with that name (__func)
	    // so call the init method passing the options if this is a object
	    else if ( typeof options === 'object' ) {
	    	return methods.init.apply( this, options );
	    }
	    // finaly call the method init passing the selector object jquery or not
	    else if ( typeof __function === 'undefined' && typeof options === 'undefined' ) {
	    	 // if only the plugin is for the type $.fn
	    	 return methods.init(this);
	    	 //return methods.init();
	    }
	    else {
	    	$.error( 'The method or event "' +  __func + '" don not exists on MyPLugin.js' );
	    }

	};

})(jQuery);
<|endoftext|>


<commit_before>import React, {Fragment} from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import {CompositeDisposable} from 'event-kit';

import URIPattern, {nonURIMatch} from './uri-pattern';
import RefHolder from '../models/ref-holder';
import StubItem from '../items/stub-item';
import {createItem, autobind} from '../helpers';

/**
 * PaneItem registers an opener with the current Atom workspace as long as this component is mounted. The opener will
 * trigger on URIs that match a specified pattern and render a subtree returned by a render prop.
 *
 * The render prop can receive three arguments:
 *
 * * itemHolder: A RefHolder. If used as the target for a ref, the referenced component will be used as the "item" of
 *   the pane item - its `getTitle()`, `getIconName()`, and other methods will be used by the pane.
 * * params: An object containing the named parameters captured by the URI pattern.
 * * uri: The exact, matched URI used to launch this item.
 *
 * render() {
 *   return (
 *     <PaneItem workspace={this.props.workspace} uriPattern='atom-github://host/{id}'>
 *       {({itemHolder, params}) => (
 *         <ItemComponent ref={itemHolder.setter} id={params.id} />
 *       )}
 *     </PaneItem>
 *   );
 * }
 */
export default class PaneItem extends React.Component {
  static propTypes = {
    workspace: PropTypes.object.isRequired,
    children: PropTypes.func.isRequired,
    uriPattern: PropTypes.string.isRequired,
    className: PropTypes.string,
  }

  constructor(props) {
    super(props);
    autobind(this, 'opener');

    const uriPattern = new URIPattern(this.props.uriPattern);
    const currentlyOpen = this.props.workspace.getPaneItems()
      .reduce((arr, item) => {
        const element = item.getElement ? item.getElement() : null;
        const match = item.getURI ? uriPattern.matches(item.getURI()) : nonURIMatch;
        const stub = item.setRealItem ? item : null;

        if (element && match.ok()) {
          const openItem = new OpenItem(match, element, stub);
          arr.push(openItem);
        }

        return arr;
      }, []);

    this.subs = new CompositeDisposable();
    this.state = {uriPattern, currentlyOpen};
  }

  static getDerivedStateFromProps(nextProps, prevState) {
    if (prevState.uriPattern.getOriginal() === nextProps.uriPattern) {
      return null;
    }

    return {
      uriPattern: new URIPattern(nextProps.uriPattern),
    };
  }

  componentDidMount() {
    // Listen for and adopt StubItems that are added after this component has
    // already been mounted.
    this.subs.add(this.props.workspace.onDidAddPaneItem(({item}) => {
      if (item.getRealItem && item.getRealItem() === null) {
        const match = this.state.uriPattern.matches(item.getURI());
        if (!match.ok()) {
          return;
        }

        const openItem = new OpenItem(match, item.getElement(), item);
        openItem.hydrateStub({
          copy: () => this.copyOpenItem(openItem),
        });
        if (this.props.className) {
          openItem.addClassName(this.props.className);
        }
        this.registerCloseListener(item, openItem);

        this.setState(prevState => ({
          currentlyOpen: [...prevState.currentlyOpen, openItem],
        }));
      }
    }));

    for (const openItem of this.state.currentlyOpen) {
      this.registerCloseListener(openItem.stubItem, openItem);

      openItem.hydrateStub({
        copy: () => this.copyOpenItem(openItem),
      });
      if (this.props.className) {
        openItem.addClassName(this.props.className);
      }
    }

    this.subs.add(this.props.workspace.addOpener(this.opener));
  }

  render() {
    return this.state.currentlyOpen.map(item => {
      return (
        <Fragment key={item.getKey()}>
          {item.renderPortal(this.props.children)}
        </Fragment>
      );
    });
  }

  componentWillUnmount() {
    this.subs.dispose();
  }

  opener(uri) {
    const m = this.state.uriPattern.matches(uri);
    if (!m.ok()) {
      return undefined;
    }

    const openItem = new OpenItem(m);
    if (this.props.className) {
      openItem.addClassName(this.props.className);
    }

    return new Promise(resolve => {
      this.setState(prevState => ({
        currentlyOpen: [...prevState.currentlyOpen, openItem],
      }), () => {
        const paneItem = openItem.create({
          copy: () => this.copyOpenItem(openItem),
        });
        this.registerCloseListener(paneItem, openItem);
        resolve(paneItem);
      });
    });
  }

  copyOpenItem(openItem) {
    const m = this.state.uriPattern.matches(openItem.getURI());
    if (!m.ok()) {
      return null;
    }

    const stub = StubItem.create('generic', openItem.getStubProps(), openItem.getURI());

    const copiedItem = new OpenItem(m, stub.getElement(), stub);
    this.setState(prevState => ({
      currentlyOpen: [...prevState.currentlyOpen, copiedItem],
    }), () => {
      this.registerCloseListener(stub, copiedItem);
      copiedItem.hydrateStub({
        copy: () => this.copyOpenItem(copiedItem),
      });
    });

    return stub;
  }

  registerCloseListener(paneItem, openItem) {
    const sub = this.props.workspace.onDidDestroyPaneItem(({item}) => {
      if (item === paneItem) {
        sub.dispose();
        this.subs.remove(sub);
        this.setState(prevState => ({
          currentlyOpen: prevState.currentlyOpen.filter(each => each !== openItem),
        }));
      }
    });

    this.subs.add(sub);
  }
}

/**
 * A subtree rendered through a portal onto a detached DOM node for use as the root as a PaneItem.
 */
class OpenItem {
  static nextID = 0

  constructor(match, element = null, stub = null) {
    this.id = this.constructor.nextID;
    this.constructor.nextID++;

    this.domNode = element || document.createElement('div');
    this.domNode.tabIndex = '-1';
    this.domNode.onfocus = this.onFocus.bind(this);
    this.stubItem = stub;
    this.stubProps = stub ? stub.props : {};
    this.match = match;
    this.itemHolder = new RefHolder();
  }

  getURI() {
    return this.match.getURI();
  }

  create(extra = {}) {
    const h = this.itemHolder.isEmpty() ? null : this.itemHolder;
    return createItem(this.domNode, h, this.match.getURI(), extra);
  }

  hydrateStub(extra = {}) {
    if (this.stubItem) {
      this.stubItem.setRealItem(this.create(extra));
      this.stubItem = null;
    }
  }

  addClassName(className) {
    this.domNode.classList.add(className);
  }

  getKey() {
    return this.id;
  }

  getStubProps() {
    const itemProps = this.itemHolder.map(item => ({
      title: item.getTitle ? item.getTitle() : null,
      iconName: item.getIconName ? item.getIconName() : null,
    }));

    return {
      ...this.stubProps,
      ...itemProps,
    };
  }

  onFocus() {
    return this.itemHolder.map(item => item.focus && item.focus());
  }

  renderPortal(renderProp) {
    return ReactDOM.createPortal(
      renderProp({
        deserialized: this.stubProps,
        itemHolder: this.itemHolder,
        params: this.match.getParams(),
        uri: this.match.getURI(),
      }),
      this.domNode,
    );
  }
}
<commit_msg>Use _getStub to identify and unwrap stubs<commit_after>import React, {Fragment} from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import {CompositeDisposable} from 'event-kit';

import URIPattern, {nonURIMatch} from './uri-pattern';
import RefHolder from '../models/ref-holder';
import StubItem from '../items/stub-item';
import {createItem, autobind} from '../helpers';

/**
 * PaneItem registers an opener with the current Atom workspace as long as this component is mounted. The opener will
 * trigger on URIs that match a specified pattern and render a subtree returned by a render prop.
 *
 * The render prop can receive three arguments:
 *
 * * itemHolder: A RefHolder. If used as the target for a ref, the referenced component will be used as the "item" of
 *   the pane item - its `getTitle()`, `getIconName()`, and other methods will be used by the pane.
 * * params: An object containing the named parameters captured by the URI pattern.
 * * uri: The exact, matched URI used to launch this item.
 *
 * render() {
 *   return (
 *     <PaneItem workspace={this.props.workspace} uriPattern='atom-github://host/{id}'>
 *       {({itemHolder, params}) => (
 *         <ItemComponent ref={itemHolder.setter} id={params.id} />
 *       )}
 *     </PaneItem>
 *   );
 * }
 */
export default class PaneItem extends React.Component {
  static propTypes = {
    workspace: PropTypes.object.isRequired,
    children: PropTypes.func.isRequired,
    uriPattern: PropTypes.string.isRequired,
    className: PropTypes.string,
  }

  constructor(props) {
    super(props);
    autobind(this, 'opener');

    const uriPattern = new URIPattern(this.props.uriPattern);
    const currentlyOpen = this.props.workspace.getPaneItems()
      .reduce((arr, item) => {
        const element = item.getElement ? item.getElement() : null;
        const match = item.getURI ? uriPattern.matches(item.getURI()) : nonURIMatch;
        const stub = item.setRealItem ? item : null;

        if (element && match.ok()) {
          const openItem = new OpenItem(match, element, stub);
          arr.push(openItem);
        }

        return arr;
      }, []);

    this.subs = new CompositeDisposable();
    this.state = {uriPattern, currentlyOpen};
  }

  static getDerivedStateFromProps(nextProps, prevState) {
    if (prevState.uriPattern.getOriginal() === nextProps.uriPattern) {
      return null;
    }

    return {
      uriPattern: new URIPattern(nextProps.uriPattern),
    };
  }

  componentDidMount() {
    // Listen for and adopt StubItems that are added after this component has
    // already been mounted.
    this.subs.add(this.props.workspace.onDidAddPaneItem(({item}) => {
      if (!item._getStub) {
        return;
      }
      const stub = item._getStub();

      if (stub.getRealItem() !== null) {
        return;
      }

      const match = this.state.uriPattern.matches(item.getURI());
      if (!match.ok()) {
        return;
      }

      const openItem = new OpenItem(match, stub.getElement(), stub);
      openItem.hydrateStub({
        copy: () => this.copyOpenItem(openItem),
      });
      if (this.props.className) {
        openItem.addClassName(this.props.className);
      }
      this.registerCloseListener(item, openItem);

      this.setState(prevState => ({
        currentlyOpen: [...prevState.currentlyOpen, openItem],
      }));
    }));

    for (const openItem of this.state.currentlyOpen) {
      this.registerCloseListener(openItem.stubItem, openItem);

      openItem.hydrateStub({
        copy: () => this.copyOpenItem(openItem),
      });
      if (this.props.className) {
        openItem.addClassName(this.props.className);
      }
    }

    this.subs.add(this.props.workspace.addOpener(this.opener));
  }

  render() {
    return this.state.currentlyOpen.map(item => {
      return (
        <Fragment key={item.getKey()}>
          {item.renderPortal(this.props.children)}
        </Fragment>
      );
    });
  }

  componentWillUnmount() {
    this.subs.dispose();
  }

  opener(uri) {
    const m = this.state.uriPattern.matches(uri);
    if (!m.ok()) {
      return undefined;
    }

    const openItem = new OpenItem(m);
    if (this.props.className) {
      openItem.addClassName(this.props.className);
    }

    return new Promise(resolve => {
      this.setState(prevState => ({
        currentlyOpen: [...prevState.currentlyOpen, openItem],
      }), () => {
        const paneItem = openItem.create({
          copy: () => this.copyOpenItem(openItem),
        });
        this.registerCloseListener(paneItem, openItem);
        resolve(paneItem);
      });
    });
  }

  copyOpenItem(openItem) {
    const m = this.state.uriPattern.matches(openItem.getURI());
    if (!m.ok()) {
      return null;
    }

    const stub = StubItem.create('generic', openItem.getStubProps(), openItem.getURI());

    const copiedItem = new OpenItem(m, stub.getElement(), stub);
    this.setState(prevState => ({
      currentlyOpen: [...prevState.currentlyOpen, copiedItem],
    }), () => {
      this.registerCloseListener(stub, copiedItem);
      copiedItem.hydrateStub({
        copy: () => this.copyOpenItem(copiedItem),
      });
    });

    return stub;
  }

  registerCloseListener(paneItem, openItem) {
    const sub = this.props.workspace.onDidDestroyPaneItem(({item}) => {
      if (item === paneItem) {
        sub.dispose();
        this.subs.remove(sub);
        this.setState(prevState => ({
          currentlyOpen: prevState.currentlyOpen.filter(each => each !== openItem),
        }));
      }
    });

    this.subs.add(sub);
  }
}

/**
 * A subtree rendered through a portal onto a detached DOM node for use as the root as a PaneItem.
 */
class OpenItem {
  static nextID = 0

  constructor(match, element = null, stub = null) {
    this.id = this.constructor.nextID;
    this.constructor.nextID++;

    this.domNode = element || document.createElement('div');
    this.domNode.tabIndex = '-1';
    this.domNode.onfocus = this.onFocus.bind(this);
    this.stubItem = stub;
    this.stubProps = stub ? stub.props : {};
    this.match = match;
    this.itemHolder = new RefHolder();
  }

  getURI() {
    return this.match.getURI();
  }

  create(extra = {}) {
    const h = this.itemHolder.isEmpty() ? null : this.itemHolder;
    return createItem(this.domNode, h, this.match.getURI(), extra);
  }

  hydrateStub(extra = {}) {
    if (this.stubItem) {
      this.stubItem.setRealItem(this.create(extra));
      this.stubItem = null;
    }
  }

  addClassName(className) {
    this.domNode.classList.add(className);
  }

  getKey() {
    return this.id;
  }

  getStubProps() {
    const itemProps = this.itemHolder.map(item => ({
      title: item.getTitle ? item.getTitle() : null,
      iconName: item.getIconName ? item.getIconName() : null,
    }));

    return {
      ...this.stubProps,
      ...itemProps,
    };
  }

  onFocus() {
    return this.itemHolder.map(item => item.focus && item.focus());
  }

  renderPortal(renderProp) {
    return ReactDOM.createPortal(
      renderProp({
        deserialized: this.stubProps,
        itemHolder: this.itemHolder,
        params: this.match.getParams(),
        uri: this.match.getURI(),
      }),
      this.domNode,
    );
  }
}
<|endoftext|>


<commit_before>(function() {

  // Ensure compatibility with CommonJS modules or browser
  var root;
  root = typeof module !== "undefined" && module.exports ? module.exports : window;

  // if Bencode is not already Defined
  if ( !root.Bencode ) {
    root.Bencode = {};
  }

  var Decode = (function() {

    var bencodedString
      , _object
      , decode
      , getType
      , getString
      , getNumber
      , getValue
      , counter
      , incrementCounter
      , setDecodedObject
    ;

    function Decode( string ) {
      bencodedString = string;
      counter = 0;

      var type = getType();

      if ( type === "string" || type === "integer" )
        return setDecodedObject( getValue( type ) );

      setDecodedObject( decode() );
    }

    decode = function() {
      var obj = getType() === "list" ? [] : {};

      incrementCounter( 1 );

      type = getType();

      while( counter < bencodedString.length ) {
        if ( obj instanceof Array ) {
          var result = isDataStructure( type ) ? decode() : getValue( type );
          obj.push( result );
        }
        else if ( obj instanceof Object ) {
          var key = getValue( type );

          type = getType();
          var value = isDataStructure( type ) ? decode() : getValue( type );

          obj[ key ] = value;
        }
        else { throw new Error("Unkown object when iterating bencoded string"); }

        if ( bencodedString.charAt( counter ) === 'e' ) {
          incrementCounter( 1 );
          return obj;
        }

        type = getType();
      }
    }

    getType = function() {
      var char = bencodedString.charAt( counter );

      if ( char.match(/\d/) ) return "string";

      switch( char ) {
        case 'i':
          return "integer";
        case 'l':
          return "list";
        case 'd':
          return "dictionary";
        default:
          throw new Error("Format unreadable");
      }
    }

    setDecodedObject = function( obj ) {
      return _object = obj;
    }

    incrementCounter = function( amount ) {
      return counter += amount
    }

    getValue = function( type ) {
      return type === "string" ? getString() : getNumber();
    }

    isDataStructure = function( type ) {
      return ( type === "list" || type === "dictionary" ) ? true : false;
    }

    getString = function() {
      var str           = bencodedString.slice( counter )
        , strArray      = str.split(':')
        , len           = strArray[0]
      ;

      incrementCounter( len.length + 1 + parseInt(len) );

      str = strArray[1];
      return str.slice(0, len );
    }

    getNumber = function() {
      var str = bencodedString.slice( counter )
        , int = str.slice( 1, str.indexOf('e') )
      ;

      incrementCounter( int.length + 2 );
      return parseInt( int );
    }

    // Public Accessor
    Decode.prototype.getDecodedObject = function() {
      return _object;
    }

    return Decode;
  })();

  String.prototype.decode = function() {
    object = new Decode( this );
    return object.getDecodedObject();
  }

  return root.Bencode.Decode = Decode;
}).call(this);
<commit_msg>remove accidental global variable<commit_after>(function() {

  // Ensure compatibility with CommonJS modules or browser
  var root;
  root = typeof module !== "undefined" && module.exports ? module.exports : window;

  // if Bencode is not already Defined
  if ( !root.Bencode ) {
    root.Bencode = {};
  }

  var Decode = (function() {

    var bencodedString
      , _object
      , decode
      , getType
      , getString
      , getNumber
      , getValue
      , counter
      , incrementCounter
      , setDecodedObject
    ;

    function Decode( string ) {
      bencodedString = string;
      counter = 0;

      var type = getType();

      if ( type === "string" || type === "integer" )
        return setDecodedObject( getValue( type ) );

      setDecodedObject( decode() );
    }

    decode = function() {
      var obj = getType() === "list" ? [] : {};

      incrementCounter( 1 );
      var type = getType();

      while( counter < bencodedString.length ) {
        if ( obj instanceof Array ) {
          var result = isDataStructure( type ) ? decode() : getValue( type );
          obj.push( result );
        }
        else if ( obj instanceof Object ) {
          var key = getValue( type );

          type = getType();
          var value = isDataStructure( type ) ? decode() : getValue( type );

          obj[ key ] = value;
        }
        else { throw new Error("Unkown object when iterating bencoded string"); }

        if ( bencodedString.charAt( counter ) === 'e' ) {
          incrementCounter( 1 );
          return obj;
        }

        type = getType();
      }
    }

    getType = function() {
      var char = bencodedString.charAt( counter );

      if ( char.match(/\d/) ) return "string";

      switch( char ) {
        case 'i':
          return "integer";
        case 'l':
          return "list";
        case 'd':
          return "dictionary";
        default:
          throw new Error("Format unreadable");
      }
    }

    setDecodedObject = function( obj ) {
      return _object = obj;
    }

    incrementCounter = function( amount ) {
      return counter += amount
    }

    getValue = function( type ) {
      return type === "string" ? getString() : getNumber();
    }

    isDataStructure = function( type ) {
      return ( type === "list" || type === "dictionary" ) ? true : false;
    }

    getString = function() {
      var str           = bencodedString.slice( counter )
        , strArray      = str.split(':')
        , len           = strArray[0]
      ;

      incrementCounter( len.length + 1 + parseInt(len) );

      str = strArray[1];
      return str.slice(0, len );
    }

    getNumber = function() {
      var str = bencodedString.slice( counter )
        , int = str.slice( 1, str.indexOf('e') )
      ;

      incrementCounter( int.length + 2 );
      return parseInt( int );
    }

    // Public Accessor
    Decode.prototype.getDecodedObject = function() {
      return _object;
    }

    return Decode;
  })();

  String.prototype.decode = function() {
    object = new Decode( this );
    return object.getDecodedObject();
  }

  return root.Bencode.Decode = Decode;
}).call(this);
<|endoftext|>


<commit_before>/**
 * Calculate the base URL
 * @return {String} [description]
 */
module.exports = function getBaseurl() {
  var sails = this;

  var usingSSL = sails.config.ssl && sails.config.ssl.key && sails.config.ssl.cert;
  var port = sails.config.proxyPort || sails.config.port;
  var localAppURL =
    (usingSSL ? 'https' : 'http') + '://' +
    (sails.getHost() || 'localhost') +
    (port == 80 || port == 443 ? '' : ':' + port);

  return localAppURL;
};
<commit_msg>fix for problem with https in #2300<commit_after>/**
 * Calculate the base URL
 * @return {String} [description]
 */
module.exports = function getBaseurl() {
  var sails = this;

  var usingSSL = sails.config.ssl && sails.config.ssl.key && sails.config.ssl.cert;
  var port = sails.config.proxyPort || sails.config.port;
  var localAppURL =
    (usingSSL || port == 443 ? 'https' : 'http') + '://' +
    (sails.getHost() || 'localhost') +
    (port == 80 || port == 443 ? '' : ':' + port);

  return localAppURL;
};
<|endoftext|>


<commit_before>"use strict";

var httpRequest = require("obsidian-http-request");
var Class = require("abitbol");
var url = require("url");
var Q = require("q");

var AssetsConverter= require("./assets-converter");
var ObsidianAssetsManager = require("./assets-manager");

/**
 * Assets catalog.
 *
 * @class obsidian-assets-manager.lib.assets-catalog
 * @constructor
 * @param {obsidian-assets-manager.lib.assets-manager} [manager]
 */
var ObsidianAssetsCatalog = Class.$extend({

    __init__: function(manager) {
        if (manager && !(manager instanceof ObsidianAssetsManager)) {
            throw Error("NotAnObsidianAssetsManager");
        }

        this.$data.manager = manager || new ObsidianAssetsManager();
        this.$data.packList = {};
        this.$data.assetList = {};
        this.$data.rootUrl = location.protocol + "//" + location.host + "/";
    },

    /**
     * The root url to resolve relative paths.
     *
     * @property rootUrl
     * @type {String}
     * @readOnly
     */
    getRootUrl: function() {
        return this.$data._rootUrl;
    },

    setRootUrl: function(rootUrl) {
        this.$data.rootUrl = url.resolve(this.$data.rootUrl, rootUrl);
    },

    /**
     * The assets manager.
     *
     * @property manager
     * @type {obsidian-assets-manager.lib.assets-manager}
     * @readOnly
     */
    getManager: function() {
        return this.$data.manager;
    },

    /**
     * Get the list of packs.
     *
     * @property packList
     * @type {Object}
     * @readOnly
     */
    getPackList: function() {
        return this.$data.packList;
    },

    /**
     * Get the list of assets.
     *
     * @property assetList
     * @type {Object}
     * @readOnly
     */
    getAssetList: function() {
        return this.$data.assetList;
    },

    // ===== Import

    /**
     * [PROMISE] Import a catalog to the catalogs list.
     *
     * @method importAssetCatalog
     * @param {Object} catalog
     * @return {Function} `function(catalogName)`
     */
    importAssetCatalog: function(catalog) {
        for (var packName in catalog.packages) {
            var pack = catalog.packages[packName];
            this.$data.packList[packName] = {
                url: pack.url,
                assets: []
            };

            for (var assetId in pack.assets) {
                var asset = pack.assets[assetId];
                assetId = "pack:" + packName + "/" + assetId;
                this.$data.packList[packName].assets.push(assetId);
                this.$data.assetList[assetId] = asset;
            }
        }

        // Stand-alone assets
        for (var standaloneAssetId in catalog.assets) {
            var standaloneAsset = catalog.assets[standaloneAssetId];
            this.$data.assetList[standaloneAssetId] = standaloneAsset;
        }

        return Q(catalog.info.name);
    },

    /**
     * [PROMISE] Import a catalog from a Url to the catalogs list.
     *
     * @method importAssetCatalogFromUrl
     * @param {String} catalogUrl
     * @return {Function} `function(catalogName)`
     */
    importAssetCatalogFromUrl: function(catalogUrl) {
        var _this = this;
        return httpRequest.getJson(url.resolve(this.$data.rootUrl, catalogUrl))
            .then(this.importAssetCatalog);
    },

    // ===== Getters

    /**
     * [PROMISE] Ensure the asset is loaded in the asset manager.
     *
     * @method loadAsset
     * @param {String} id
     * @return {String}
     */
    loadAsset: function(id) {
        if (this.assetLoaded(id)) {
            return Q(id);
        }

        var asset = this.$data.assetList[id];
        if (!asset) {
            throw Error("Asset '" + id + "' does not exist");
        }

        var source = id.split(":")[0];

        // No source, it's a standalone asset
        if (source === id) {
            var assetUrl = url.resolve(this.$data.rootUrl, asset.url);
            return this.$data.manager.addAssetFromUrl(assetUrl, {
                id: id,
                mime: asset.mime,
                metadata: asset.metadata
            });
        }

        // It's from a pack
        else if (source === "pack") {
            var packName = id.split(":")[1].split("/")[0];
            var pack = this.$data.packList[packName];

            if (!pack) {
                throw Error("Pack '" + packName + "' does not exist");
            }

            var packUrl = url.resolve(this.$data.rootUrl, pack.url);
            return this.$data.manager.importAssetPackageFromUrl(packUrl)
                .then(function(pack) {
                    if (pack.packName !== packName) {
                        throw new Error("Pack name '" + packName + "' in catalog is different from the one in the package itself '" + pack.packName + "'");
                    }
                    return Q(id);
                });
        }

        throw Error("Asset '" + id + "' does not exist");
    },

    /**
     * [PROMISE] Get an asset as a buffer.
     *
     * @method getAssetAsBuffer
     * @param {String} id
     * @return {Function} `function(buffer)`
     */
    getAssetAsBuffer: function(id) {
        return this.loadAsset(id)
            .then(this.$data.manager.getAssetAsBuffer);
    },

    /**
     * [PROMISE] Get an asset as an image.
     *
     * @method getAssetAsImage
     * @param {String} id
     * @return {Function} `function(image)`
     */
    getAssetAsImage: function(id) {
        return this.loadAsset(id)
            .then(this.$data.manager.getAssetAsImage);
    },

    /**
     * [PROMISE] Get an asset as a blob URL.
     *
     * @method getAssetAsBlobUrl
     * @param {String} id
     * @return {Function} `function(url)`
     */
    getAssetAsBlobUrl: function(id) {
        return this.loadAsset(id)
            .then(this.$data.manager.getAssetAsBlobUrl);
    },

    /**
     * [PROMISE] Get an asset as a data-64 URL.
     *
     * @method getAssetAsData64Url
     * @param {String} id
     * @return {Function} `function(data64Url)`
     */
    getAssetAsData64Url: function(id) {
        return this.loadAsset(id)
            .then(this.$data.manager.getAssetAsData64Url);
    },

    /**
     * [PROMISE] Get an asset as a blob.
     *
     * @method getAssetAsBlob
     * @param {String} id
     * @return {Function} `function(blob)`
     */
    getAssetAsBlob: function(id) {
        return this.loadAsset(id)
            .then(this.$data.manager.getAssetAsBlob);
    },

    /**
     * Get the record of a asset.
     *
     *     record: {
     *         mime,    // {String}
     *         offset,  // {Number}
     *         length,  // {Number}
     *         metadata // {Object}
     *     };
     *
     * @param {String} id
     * @return {Object}
     */
    getAssetRecord: function(id) {
        return this.$data.assetList[id];
    },

    // ===== Utilities

    /**
     * Check whether the specified asset exists or not.
     *
     * @method assetExists
     * @param {String} id
     * @return {Boolean}
     */
    assetExists: function(id) {
        var asset = this.$data.assetList[id];
        return asset !== undefined;
    },

    /**
     * Check whether the specified asset has been loaded or not.
     *
     * @method assetLoaded
     * @param {String} id
     * @return {Boolean}
     */
    assetLoaded: function(id) {
        return this.$data.manager.assetExists(id);
    }

});

module.exports = ObsidianAssetsCatalog;
<commit_msg>Removed necessity to have the info section in a catalog<commit_after>"use strict";

var httpRequest = require("obsidian-http-request");
var Class = require("abitbol");
var url = require("url");
var Q = require("q");

var AssetsConverter= require("./assets-converter");
var ObsidianAssetsManager = require("./assets-manager");

/**
 * Assets catalog.
 *
 * @class obsidian-assets-manager.lib.assets-catalog
 * @constructor
 * @param {obsidian-assets-manager.lib.assets-manager} [manager]
 */
var ObsidianAssetsCatalog = Class.$extend({

    __init__: function(manager) {
        if (manager && !(manager instanceof ObsidianAssetsManager)) {
            throw Error("NotAnObsidianAssetsManager");
        }

        this.$data.manager = manager || new ObsidianAssetsManager();
        this.$data.packList = {};
        this.$data.assetList = {};
        this.$data.rootUrl = location.protocol + "//" + location.host + "/";
    },

    /**
     * The root url to resolve relative paths.
     *
     * @property rootUrl
     * @type {String}
     * @readOnly
     */
    getRootUrl: function() {
        return this.$data._rootUrl;
    },

    setRootUrl: function(rootUrl) {
        this.$data.rootUrl = url.resolve(this.$data.rootUrl, rootUrl);
    },

    /**
     * The assets manager.
     *
     * @property manager
     * @type {obsidian-assets-manager.lib.assets-manager}
     * @readOnly
     */
    getManager: function() {
        return this.$data.manager;
    },

    /**
     * Get the list of packs.
     *
     * @property packList
     * @type {Object}
     * @readOnly
     */
    getPackList: function() {
        return this.$data.packList;
    },

    /**
     * Get the list of assets.
     *
     * @property assetList
     * @type {Object}
     * @readOnly
     */
    getAssetList: function() {
        return this.$data.assetList;
    },

    // ===== Import

    /**
     * [PROMISE] Import a catalog to the catalogs list.
     *
     * @method importAssetCatalog
     * @param {Object} catalog
     * @return {Function} `function(catalogName)` if name is defined in the info section
     */
    importAssetCatalog: function(catalog) {
        for (var packName in catalog.packages) {
            var pack = catalog.packages[packName];
            this.$data.packList[packName] = {
                url: pack.url,
                assets: []
            };

            for (var assetId in pack.assets) {
                var asset = pack.assets[assetId];
                assetId = "pack:" + packName + "/" + assetId;
                this.$data.packList[packName].assets.push(assetId);
                this.$data.assetList[assetId] = asset;
            }
        }

        // Stand-alone assets
        for (var standaloneAssetId in catalog.assets) {
            var standaloneAsset = catalog.assets[standaloneAssetId];
            this.$data.assetList[standaloneAssetId] = standaloneAsset;
        }

        if (catalog.info) {
            return Q(catalog.info.name);
        }
    },

    /**
     * [PROMISE] Import a catalog from a Url to the catalogs list.
     *
     * @method importAssetCatalogFromUrl
     * @param {String} catalogUrl
     * @return {Function} `function(catalogName)`
     */
    importAssetCatalogFromUrl: function(catalogUrl) {
        var _this = this;
        return httpRequest.getJson(url.resolve(this.$data.rootUrl, catalogUrl))
            .then(this.importAssetCatalog);
    },

    // ===== Getters

    /**
     * [PROMISE] Ensure the asset is loaded in the asset manager.
     *
     * @method loadAsset
     * @param {String} id
     * @return {String}
     */
    loadAsset: function(id) {
        if (this.assetLoaded(id)) {
            return Q(id);
        }

        var asset = this.$data.assetList[id];
        if (!asset) {
            throw Error("Asset '" + id + "' does not exist");
        }

        var source = id.split(":")[0];

        // No source, it's a standalone asset
        if (source === id) {
            var assetUrl = url.resolve(this.$data.rootUrl, asset.url);
            return this.$data.manager.addAssetFromUrl(assetUrl, {
                id: id,
                mime: asset.mime,
                metadata: asset.metadata
            });
        }

        // It's from a pack
        else if (source === "pack") {
            var packName = id.split(":")[1].split("/")[0];
            var pack = this.$data.packList[packName];

            if (!pack) {
                throw Error("Pack '" + packName + "' does not exist");
            }

            var packUrl = url.resolve(this.$data.rootUrl, pack.url);
            return this.$data.manager.importAssetPackageFromUrl(packUrl)
                .then(function(pack) {
                    if (pack.packName !== packName) {
                        throw new Error("Pack name '" + packName + "' in catalog is different from the one in the package itself '" + pack.packName + "'");
                    }
                    return Q(id);
                });
        }

        throw Error("Asset '" + id + "' does not exist");
    },

    /**
     * [PROMISE] Get an asset as a buffer.
     *
     * @method getAssetAsBuffer
     * @param {String} id
     * @return {Function} `function(buffer)`
     */
    getAssetAsBuffer: function(id) {
        return this.loadAsset(id)
            .then(this.$data.manager.getAssetAsBuffer);
    },

    /**
     * [PROMISE] Get an asset as an image.
     *
     * @method getAssetAsImage
     * @param {String} id
     * @return {Function} `function(image)`
     */
    getAssetAsImage: function(id) {
        return this.loadAsset(id)
            .then(this.$data.manager.getAssetAsImage);
    },

    /**
     * [PROMISE] Get an asset as a blob URL.
     *
     * @method getAssetAsBlobUrl
     * @param {String} id
     * @return {Function} `function(url)`
     */
    getAssetAsBlobUrl: function(id) {
        return this.loadAsset(id)
            .then(this.$data.manager.getAssetAsBlobUrl);
    },

    /**
     * [PROMISE] Get an asset as a data-64 URL.
     *
     * @method getAssetAsData64Url
     * @param {String} id
     * @return {Function} `function(data64Url)`
     */
    getAssetAsData64Url: function(id) {
        return this.loadAsset(id)
            .then(this.$data.manager.getAssetAsData64Url);
    },

    /**
     * [PROMISE] Get an asset as a blob.
     *
     * @method getAssetAsBlob
     * @param {String} id
     * @return {Function} `function(blob)`
     */
    getAssetAsBlob: function(id) {
        return this.loadAsset(id)
            .then(this.$data.manager.getAssetAsBlob);
    },

    /**
     * Get the record of a asset.
     *
     *     record: {
     *         mime,    // {String}
     *         offset,  // {Number}
     *         length,  // {Number}
     *         metadata // {Object}
     *     };
     *
     * @param {String} id
     * @return {Object}
     */
    getAssetRecord: function(id) {
        return this.$data.assetList[id];
    },

    // ===== Utilities

    /**
     * Check whether the specified asset exists or not.
     *
     * @method assetExists
     * @param {String} id
     * @return {Boolean}
     */
    assetExists: function(id) {
        var asset = this.$data.assetList[id];
        return asset !== undefined;
    },

    /**
     * Check whether the specified asset has been loaded or not.
     *
     * @method assetLoaded
     * @param {String} id
     * @return {Boolean}
     */
    assetLoaded: function(id) {
        return this.$data.manager.assetExists(id);
    }

});

module.exports = ObsidianAssetsCatalog;
<|endoftext|>