<commit_before>function BowlingGame() {
  this.ball = 1;
  this.frameCounter = 1;
  this.frameHolder = [];
  this.rollTracker = [];
};

BowlingGame.prototype.roll = function(pins){
  this.rollTracker.push(pins);
  if ( this.ball === 1 ) {
        this.frameHolder[0] = pins;
        this.ball++;
        return this.frameValidate();
  } else if ( this.ball === 2 ) {
        this.frameHolder[1] = pins;
        return this.frameValidate();
        this.nextFrame();
  } else if ( this.ball === 3 ) {
        this.frameHolder[2] = pins;
        return this.frameValidate();
  }
};

BowlingGame.prototype.frameValidate = function() {
  validate = this.frameHolder.reduce(function(a,b){
    return a+b;
  });
    if ( validate > 10 && this.frameCounter != 10 ) {
      this.ball = 2;
      this.rollTracker.pop();
      this.frameHolder.pop();
      throw new Error("Oops! You can't hit more than 10 pins per frame!");
  } else if ( this.frameHolder[0] === 10 && this.frameCounter != 10) {
      this.nextFrame();
      return 'X';
  } else if ( validate === 10 && this.ball === 2 && this.frameCounter != 10 ) {
      this.nextFrame();
      return '/';
  } else if ( this.frameHolder.length === 2 && this.frameCounter != 10 ) {
      this.nextFrame();
  }

  else if ( this.frameHolder[0] === 10 && this.frameHolder.length === 1 && this.frameCounter === 10 ) {
      return 'Strike bonus roll 1';
  } else if (this.frameHolder[0] === 10 && this.frameHolder[1] === 10 && this.frameHolder.length === 2 && this.frameCounter === 10 ){
      this.ball = 3;
      return "Strike bonus roll 2";
  } else if ( this.frameHolder[0] === 10 && this.frameHolder[1] === 10 && this.frameHolder[2] === 10 && this.frameHolder.length === 3 && this.frameCounter === 10 ){
      return "Game Over! Your Score: " + this.score();

  } else if ( validate === 10 && this.frameHolder.length === 2 && this.frameCounter === 10 ) {
      this.ball++;
      return 'Spare bonus roll';
  } else if ( validate != 30 && this.frameHolder.length === 3 && this.frameCounter === 10 ) {
      return "Game Over! Your Score: " + this.score();
  } else if ( validate != 10 && this.frameHolder.length === 2 && this.frameCounter === 10 ) {
      return "Game Over! Your Score: " + this.score();
  }
};

BowlingGame.prototype.nextFrame = function(){
  this.ball = 1;
  this.frameCounter++;
  this.frameHolder = [];
  if ( this.frameCounter > 10 ) {
      throw new Error("You've played 10 frames, start a new game!")
  }
};

BowlingGame.prototype.autoRoll = function(){
  pins = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  if ( this.ball === 1 ) {
      roll_1 = pins[Math.floor(Math.random() * pins.length)];
      this.rollTracker.push(roll_1);
      this.frameHolder[0] = roll_1;
      this.ball++;
      return roll_1;
  } else if ( this.ball === 2 ) {
      roll_2 = pins[Math.floor(Math.random() * pins.length)];
      this.rollTracker.push(roll_2);
      this.frameHolder[1] = roll_2;
      this.autoFrameValidate();
      return roll_2;
  }
};

BowlingGame.prototype.autoFrameValidate = function() {
  validate = this.frameHolder.reduce(function(a,b){
    return a+b;
  });
      if (validate > 10 ) {
        this.rollTracker.pop();
        this.frameHolder.pop();
        this.autoRoll().roll_2;
    } else {
      return this.frameValidate();
    }
  };

BowlingGame.prototype.score = function() {
  let calc = 0;
  let i = 0;
  for (var frame = 0; frame < 10; frame++) {
      if (this.scoreStrike(i)) {
          calc += 10 + this.rollTracker[i+1] + this.rollTracker[i+2];
          i++;
      } else if (this.scoreSpare(i)){
          calc += 10 + this.rollTracker[i+2];
          i+=2;
      } else {
          calc += this.rollTracker[i] + this.rollTracker[i+1];
          i+=2;
      }
  }
  return calc;
};

BowlingGame.prototype.gameOver = function() {
  return 'game over';
  if (this.score() < 150 ) {
        return "Ouch you need practice!";
        return 'your final score:' + this.score();
  } else if (this.score() > 250 ) {
        return "Woah! Are you a bowling pro?!";
        return 'your final score:' + this.score();
  } else {
        return "Not too bad, keep bowling!";
        return 'your final score:' + this.score();
  }
};

BowlingGame.prototype.frameLayout = function(){
  frames = this.rollTracker;
  frame = 1;
  for (i = 0; frames; i++) {
    // add logic for returning frames in pairs from index 0
  }
};

BowlingGame.prototype.scoreSpare = function(i) {
  return this.rollTracker[i] + this.rollTracker[i+1] === 10;
};

BowlingGame.prototype.scoreStrike = function(i) {
  return this.rollTracker[i] === 10;
};
<commit_msg>Game reset works<commit_after>function BowlingGame() {
  this.ball = 1;
  this.frameCounter = 1;
  this.frameHolder = [];
  this.rollTracker = [];
};

BowlingGame.prototype.roll = function(pins){
  this.rollTracker.push(pins);
  if ( this.ball === 1 ) {
        this.frameHolder[0] = pins;
        this.ball++;
        return this.frameValidate();
  } else if ( this.ball === 2 ) {
        this.frameHolder[1] = pins;
        return this.frameValidate();
        this.nextFrame();
  } else if ( this.ball === 3 ) {
        this.frameHolder[2] = pins;
        return this.frameValidate();
  } else if ( this.ball === 4 ) {
        return this.gameReset();
  }
};

BowlingGame.prototype.frameValidate = function() {
  validate = this.frameHolder.reduce(function(a,b){
    return a+b;
  });
    if ( validate > 10 && this.frameCounter != 10 ) {
      this.ball = 2;
      this.rollTracker.pop();
      this.frameHolder.pop();
      throw new Error("Oops! You can't hit more than 10 pins per frame!");
  } else if ( this.frameHolder[0] === 10 && this.frameCounter != 10) {
      this.nextFrame();
      return 'X';
  } else if ( validate === 10 && this.ball === 2 && this.frameCounter != 10 ) {
      this.nextFrame();
      return '/';
  } else if ( this.frameHolder.length === 2 && this.frameCounter != 10 ) {
      this.nextFrame();
  }

  else if ( this.frameHolder[0] === 10 && this.frameHolder.length === 1 && this.frameCounter === 10 ) {
      return 'Strike bonus roll 1';
  } else if (this.frameHolder[0] === 10 && this.frameHolder[1] === 10 && this.frameHolder.length === 2 && this.frameCounter === 10 ){
      this.ball = 3;
      return "Strike bonus roll 2";
  } else if ( this.frameHolder[0] === 10 && this.frameHolder[1] === 10 && this.frameHolder[2] === 10 && this.frameHolder.length === 3 && this.frameCounter === 10 ){
      this.ball++;
      return "Game Over! Your Score: " + this.score();
      this.gameReset();

  } else if ( validate === 10 && this.frameHolder.length === 2 && this.frameCounter === 10 ) {
      this.ball++;
      return 'Spare bonus roll';
  } else if ( validate != 30 && this.frameHolder.length === 3 && this.frameCounter === 10 ) {
      return "Game Over! Your Score: " + this.score();
  } else if ( validate != 10 && this.frameHolder.length === 2 && this.frameCounter === 10 ) {
      return "Game Over! Your Score: " + this.score();
  }
};

BowlingGame.prototype.nextFrame = function(){
  this.ball = 1;
  this.frameCounter++;
  this.frameHolder = [];
  if ( this.frameCounter > 10 ) {
      throw new Error("You've played 10 frames, start a new game!")
  }
};

BowlingGame.prototype.autoRoll = function(){
  pins = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  if ( this.ball === 1 ) {
      roll_1 = pins[Math.floor(Math.random() * pins.length)];
      this.rollTracker.push(roll_1);
      this.frameHolder[0] = roll_1;
      this.ball++;
      return roll_1;
  } else if ( this.ball === 2 ) {
      roll_2 = pins[Math.floor(Math.random() * pins.length)];
      this.rollTracker.push(roll_2);
      this.frameHolder[1] = roll_2;
      this.autoFrameValidate();
      return roll_2;
  }
};

BowlingGame.prototype.autoFrameValidate = function() {
  validate = this.frameHolder.reduce(function(a,b){
    return a+b;
  });
      if (validate > 10 ) {
        this.rollTracker.pop();
        this.frameHolder.pop();
        this.autoRoll().roll_2;
    } else {
      return this.frameValidate();
    }
  };

BowlingGame.prototype.score = function() {
  let calc = 0;
  let i = 0;
  for (var frame = 0; frame < 10; frame++) {
      if (this.scoreStrike(i)) {
          calc += 10 + this.rollTracker[i+1] + this.rollTracker[i+2];
          i++;
      } else if (this.scoreSpare(i)){
          calc += 10 + this.rollTracker[i+2];
          i+=2;
      } else {
          calc += this.rollTracker[i] + this.rollTracker[i+1];
          i+=2;
      }
  }
  return calc;
};

BowlingGame.prototype.gameReset = function(){
  this.rollTracker = [];
  this.ball = 1;
  this.frameHolder = [];
  this.frameCounter = 1;
  return "You've started a new game of 10 pin bowling!";
};

BowlingGame.prototype.frameLayout = function(){
  frames = this.rollTracker;
  frame = 1;
  for (i = 0; frames; i++) {
    // add logic for returning frames in pairs from index 0
  }
};

BowlingGame.prototype.scoreSpare = function(i) {
  return this.rollTracker[i] + this.rollTracker[i+1] === 10;
};

BowlingGame.prototype.scoreStrike = function(i) {
  return this.rollTracker[i] === 10;
};
<|endoftext|>


<commit_before>'use strict';

const Layer = require('./../Stack/Layers/Layer');
const MessageRouter = require('./Objects/MessageRouter');

class ControlLogix extends Layer {
  constructor(connectionLayer, options) {
    super(connectionLayer);
  }

  ReadTag(address, callback) {
    const BASE_ERROR = 'ControlLogix Error: Read Tag: ';
    if (callback == null) return;

    if (address == null || address.length === 0) {
      callback(BASE_ERROR + 'Address must be specified');
      return;
    }

    let path = MessageRouter.ANSIExtSymbolSegment(address);
    const data = Buffer.from([0x01, 0x00]); // number of elements to read (1)

    let request = MessageRouter.Request(Services.ReadTag, path, data);

    this.send(request, null, false, this.contextCallback(function(message) {
      let reply = MessageRouter.Reply(message);

      if (reply.statusCode !== 0) {
        if (READ_TAG_ERRORS[reply.statusCode] != null) {
          reply.statusDescription = READ_TAG_ERRORS[reply.statusCode];
        }
        callback(BASE_ERROR + reply.statusDescription);
        return;
      }

      let dataType = reply.data.readUInt16LE(0);
      let dataConverter = DataConverters[dataType];
      if (dataConverter) {
        callback(null, dataConverter(reply.data, 2));
      } else {
        callback(BASE_ERROR + 'No converter for data type: ' + dataType);
      }
    }));
  }

  WriteTag(address, value, callback) {
    const BASE_ERROR = 'ControlLogix Error: Write Tag: ';
    if (address == null || address.length === 0) {
      if (callback != null) {
        callback(BASE_ERROR + 'Address must be specified');
      }
      return;
    }

    let path = MessageRouter.ANSIExtSymbolSegment(address);
    let data = Buffer.alloc(8);
    data.writeUInt16LE(DataTypes.Float, 0);
    data.writeUInt16LE(1, 2);
    data.writeFloatLE(value, 4);

    let request = MessageRouter.Request(Services.WriteTag, path, data);

    this.send(request, function(message) {
      let reply = MessageRouter.Reply(message);
      if (callback != null) callback(null, reply);
    });
  }

  ReadModifyWriteTag(address, sizeOfMasks ORmasks, ANDmasks, callback) {
    const BASE_ERROR = 'ControlLogix Error: Read Modify Write Tag: ';
    if (address == null || address.length === 0) {
      if (callback != null) {
        callback(BASE_ERROR + 'Address must be specified');
      }
      return;
    }

  }

  handleData(data, info, context) {
    if (context == null) {
      throw new Error('ControlLogix Error: Unhandled message, context should not be null');
    }

    let callback = this.getCallbackForContext(context);
    if (callback != null) {
      callback(data, info);
    }
  }
}

module.exports = ControlLogix;

// 1756-PM020, pg. 16
const Services = {
  ReadTag: 0x4C,
  ReadTagFragmented: 0x52,
  WriteTag: 0x4D,
  WriteTagFragmented: 0x53,
  ReadModifyWriteTag: 0x4E,

  MultipleServicePacket: 0x0A // used to combine multiple requests in one message frame
};

const DataTypes = {
  Byte: 0xC1,
  Char: 0xC2,
  Short: 0xC3,
  Integer: 0xC4,
  Float: 0xCA,
  UnsignedInteger: 0xD3
}

const DataConverters = {
  0x00C1: function(buffer, offset) {
    return !!buffer.readUInt8(offset);
  },
  0x00C2: function(buffer, offset) {
    return buffer.readInt8(offset);
  },
  0x00C3: function(buffer, offset) {
    return buffer.readInt16LE(offset);
  },
  0x00C4: function(buffer, offset) {
    return buffer.readInt32(offset);
  },
  0x00CA: function(buffer, offset) {
    return buffer.readFloatLE(offset);
  },
  0x00D3: function(buffer, offset) {
    return buffer.readUInt32LE(offset);
  }
};

// CIP Logix5000 1756-PM020 Page 19, Read Tag Service Error Codes
const READ_TAG_ERRORS = {
  0x04: 'A syntax error was detected decoding the Request Path',
  0x05: 'Request Path destination unknown: Probably instance number is not present',
  0x06: 'Insufficient Packet Space: Not enough room in the response buffer for all the data',
  0x13: 'Insufficient Request Data: Data too short for expected parameters',
  0x26: 'The Request Path Size received was shorter or longer than expected',
  0xFF: 'General Error: Access beyond end of the object'
};
<commit_msg>Use context for callbacks<commit_after>'use strict';

const Layer = require('./../Stack/Layers/Layer');
const MessageRouter = require('./Objects/MessageRouter');

class ControlLogix extends Layer {
  constructor(connectionLayer, options) {
    super(connectionLayer);
  }

  ReadTag(address, callback) {
    const BASE_ERROR = 'ControlLogix Error: Read Tag: ';
    if (callback == null) return;

    if (address == null || address.length === 0) {
      callback(BASE_ERROR + 'Address must be specified');
      return;
    }

    let path = MessageRouter.ANSIExtSymbolSegment(address);
    const data = Buffer.from([0x01, 0x00]); // number of elements to read (1)

    let request = MessageRouter.Request(Services.ReadTag, path, data);

    this.send(request, null, false, this.contextCallback(function(message) {
      let reply = MessageRouter.Reply(message);

      if (reply.statusCode !== 0) {
        if (READ_TAG_ERRORS[reply.statusCode] != null) {
          reply.statusDescription = READ_TAG_ERRORS[reply.statusCode];
        }
        callback(BASE_ERROR + reply.statusDescription);
        return;
      }

      let dataType = reply.data.readUInt16LE(0);
      let dataConverter = DataConverters[dataType];
      if (dataConverter) {
        callback(null, dataConverter(reply.data, 2));
      } else {
        callback(BASE_ERROR + 'No converter for data type: ' + dataType);
      }
    }));
  }

  WriteTag(address, value, callback) {
    const BASE_ERROR = 'ControlLogix Error: Write Tag: ';
    if (address == null || address.length === 0) {
      if (callback != null) {
        callback(BASE_ERROR + 'Address must be specified');
      }
      return;
    }

    let path = MessageRouter.ANSIExtSymbolSegment(address);
    let data = Buffer.alloc(8);
    data.writeUInt16LE(DataTypes.Float, 0);
    data.writeUInt16LE(1, 2);
    data.writeFloatLE(value, 4);

    let request = MessageRouter.Request(Services.WriteTag, path, data);

    this.send(request, null, false, this.contextCallback(function(message) {
      let reply = MessageRouter.Reply(message);
      if (callback != null) callback(null, reply);
    }));
  }

  ReadModifyWriteTag(address, sizeOfMasks ORmasks, ANDmasks, callback) {
    const BASE_ERROR = 'ControlLogix Error: Read Modify Write Tag: ';
    if (address == null || address.length === 0) {
      if (callback != null) {
        callback(BASE_ERROR + 'Address must be specified');
      }
      return;
    }

  }

  handleData(data, info, context) {
    if (context == null) {
      throw new Error('ControlLogix Error: Unhandled message, context should not be null');
    }

    let callback = this.getCallbackForContext(context);
    if (callback != null) {
      callback(data, info);
    }
  }
}

module.exports = ControlLogix;

// 1756-PM020, pg. 16
const Services = {
  ReadTag: 0x4C,
  ReadTagFragmented: 0x52,
  WriteTag: 0x4D,
  WriteTagFragmented: 0x53,
  ReadModifyWriteTag: 0x4E,

  MultipleServicePacket: 0x0A // used to combine multiple requests in one message frame
};

const DataTypes = {
  Byte: 0xC1,
  Char: 0xC2,
  Short: 0xC3,
  Integer: 0xC4,
  Float: 0xCA,
  UnsignedInteger: 0xD3
}

const DataConverters = {
  0x00C1: function(buffer, offset) {
    return !!buffer.readUInt8(offset);
  },
  0x00C2: function(buffer, offset) {
    return buffer.readInt8(offset);
  },
  0x00C3: function(buffer, offset) {
    return buffer.readInt16LE(offset);
  },
  0x00C4: function(buffer, offset) {
    return buffer.readInt32(offset);
  },
  0x00CA: function(buffer, offset) {
    return buffer.readFloatLE(offset);
  },
  0x00D3: function(buffer, offset) {
    return buffer.readUInt32LE(offset);
  }
};

// CIP Logix5000 1756-PM020 Page 19, Read Tag Service Error Codes
const READ_TAG_ERRORS = {
  0x04: 'A syntax error was detected decoding the Request Path',
  0x05: 'Request Path destination unknown: Probably instance number is not present',
  0x06: 'Insufficient Packet Space: Not enough room in the response buffer for all the data',
  0x13: 'Insufficient Request Data: Data too short for expected parameters',
  0x26: 'The Request Path Size received was shorter or longer than expected',
  0xFF: 'General Error: Access beyond end of the object'
};
<|endoftext|>


<commit_before>// @flow

import React from 'react';
import { mount } from 'enzyme';
import renderer from 'react-test-renderer';
import { Provider } from 'mobx-react';
import AccordionItemTitle from '../AccordionItemTitle/accordion-item-title';
import AccordionItemBody from '../AccordionItemBody/accordion-item-body';
import AccordionItem from './accordion-item';
import { createAccordionStore } from '../accordionStore/accordionStore';

jest.mock('consecutive', () => () => () => 'mock-uuid-hash');

describe('AccordionItem', () => {
    let accordionStore;

    beforeEach(() => {
        accordionStore = createAccordionStore({
            accordion: false,
            onChange: jest.fn(),
        });
    });

    it('renders correctly with accordion true', () => {
        accordionStore.accordion = true;
        const tree = renderer
            .create(
                <Provider accordionStore={accordionStore}>
                    <AccordionItem className="accordion__item">
                        <AccordionItemTitle className="accordion__title">

Fake title

                        </AccordionItemTitle>
                        <AccordionItemBody className="accordion__body">

Fake body

                        </AccordionItemBody>
                    </AccordionItem>
                </Provider>,
            )
            .toJSON();
        expect(tree).toMatchSnapshot();
    });

    it('renders correctly with accordion false', () => {
        accordionStore.accordion = false;
        const tree = renderer
            .create(
                <Provider accordionStore={accordionStore}>
                    <AccordionItem className="accordion__item">
                        <AccordionItemTitle className="accordion__title">

Fake title

                        </AccordionItemTitle>
                        <AccordionItemBody className="accordion__body">

Fake body

                        </AccordionItemBody>
                    </AccordionItem>
                </Provider>,
            )
            .toJSON();
        expect(tree).toMatchSnapshot();
    });

    it('still renders with no AccordionItemTitle or AccordionItemBody', () => {
        const tree = renderer
            .create(
                <Provider accordionStore={accordionStore}>
                    <AccordionItem>

Fake title

Fake body

                    </AccordionItem>
                </Provider>,
            )
            .toJSON();
        expect(tree).toMatchSnapshot();
    });

    it('still renders with no children at all', () => {
        const tree = renderer
            .create(
                <Provider accordionStore={accordionStore}>
                    <AccordionItem />
                </Provider>,
            )
            .toJSON();
        expect(tree).toMatchSnapshot();
    });

    it('renders with different className', () => {
        const tree = renderer.create(
            <Provider accordionStore={accordionStore}>
                <AccordionItem className="testCSSClass" />
            </Provider>,
        );
        expect(tree.root.findByType('div').props.className).toEqual(
            'testCSSClass',
        );
    });

    it('renders with different hideBodyClassName', () => {
        const tree = renderer.create(
            <Provider accordionStore={accordionStore}>
                <AccordionItem
                    expanded={false}
                    className="accordion-item"
                    hideBodyClassName="accordion-item--hidden"
                />
            </Provider>,
        );
        expect(tree.root.findByType('div').props.className).toEqual(
            'accordion-item accordion-item--hidden',
        );
    });

    it('renders correctly with other blocks inside', () => {
        const tree = renderer
            .create(
                <Provider accordionStore={accordionStore}>
                    <AccordionItem accordion={false}>
                        <AccordionItemTitle>

Fake title

                        </AccordionItemTitle>

Just another block

                        <AccordionItemBody>

Fake body

                        </AccordionItemBody>
                    </AccordionItem>
                </Provider>,
            )
            .toJSON();
        expect(tree).toMatchSnapshot();
    });

    it('renders correctly with other blocks inside 2', () => {
        const tree = renderer
            .create(
                <Provider accordionStore={accordionStore}>
                    <AccordionItem accordion={false}>
                        <AccordionItemTitle>

Fake title

                        </AccordionItemTitle>
                        <AccordionItemBody>

Fake body

                        </AccordionItemBody>

Just another block

                    </AccordionItem>
                </Provider>,
            )
            .toJSON();
        expect(tree).toMatchSnapshot();
    });

    it('can dynamically set expanded prop', () => {
        const Wrapper = ({ expanded }: { expanded: boolean }) => (
            <Provider accordionStore={accordionStore}>
                <AccordionItem expanded={expanded}>
                    <AccordionItemTitle>

Fake title

                    </AccordionItemTitle>
                </AccordionItem>
            </Provider>
        );
        const wrapper = mount(<Wrapper expanded={false} />);
        wrapper.setProps({ expanded: true });

        expect(
            accordionStore.items.filter(item => item.expanded === true).length,
        ).toEqual(1);
    });

    it('can dynamically set activeItems', () => {
        accordionStore.activeItems = ['foo'];
        mount(
            <Provider accordionStore={accordionStore}>
                <AccordionItem itemkey="foo">
                    <AccordionItemTitle>

Fake title

                    </AccordionItemTitle>
                </AccordionItem>
            </Provider>,
        );

        expect(
            accordionStore.items.filter(item => item.expanded === true).length,
        ).toEqual(1);
    });

    it('can dynamically toggle activeItems', () => {
        accordionStore.activeItems = [];
        mount(
            <Provider accordionStore={accordionStore}>
                <AccordionItem itemkey="foo">
                    <AccordionItemTitle>

Fake title

                    </AccordionItemTitle>
                </AccordionItem>
            </Provider>,
        );
        accordionStore.activeItems = ['foo'];

        const fooItem = accordionStore.items.find(
            item => item.itemkey === 'foo',
        );

        expect(fooItem && fooItem.expanded).toEqual(true);
    });
});
<commit_msg>Add test for rendering multiple items<commit_after>// @flow

import React from 'react';
import { mount } from 'enzyme';
import renderer from 'react-test-renderer';
import { Provider } from 'mobx-react';
import AccordionItemTitle from '../AccordionItemTitle/accordion-item-title';
import AccordionItemBody from '../AccordionItemBody/accordion-item-body';
import AccordionItem from './accordion-item';
import { createAccordionStore } from '../accordionStore/accordionStore';

jest.mock('consecutive', () => () => () => 'mock-uuid-hash');

describe('AccordionItem', () => {
    let accordionStore;

    beforeEach(() => {
        accordionStore = createAccordionStore({
            accordion: false,
            onChange: jest.fn(),
        });
    });

    it('renders correctly with accordion true', () => {
        accordionStore.accordion = true;
        const tree = renderer
            .create(
                <Provider accordionStore={accordionStore}>
                    <AccordionItem className="accordion__item">
                        <AccordionItemTitle className="accordion__title">

Fake title

                        </AccordionItemTitle>
                        <AccordionItemBody className="accordion__body">

Fake body

                        </AccordionItemBody>
                    </AccordionItem>
                </Provider>,
            )
            .toJSON();
        expect(tree).toMatchSnapshot();
    });

    it('renders correctly with accordion false', () => {
        accordionStore.accordion = false;
        const tree = renderer
            .create(
                <Provider accordionStore={accordionStore}>
                    <AccordionItem className="accordion__item">
                        <AccordionItemTitle className="accordion__title">

Fake title

                        </AccordionItemTitle>
                        <AccordionItemBody className="accordion__body">

Fake body

                        </AccordionItemBody>
                    </AccordionItem>
                </Provider>,
            )
            .toJSON();
        expect(tree).toMatchSnapshot();
    });

    it('renders with multiple AccordionItems', () => {
        const wrapper = mount(
            <Provider accordionStore={accordionStore}>

                    <AccordionItem>

Fake title

Fake body

                    </AccordionItem>
                    <AccordionItem>

Fake title

Fake body

                    </AccordionItem>

            </Provider>,
        );
        expect(wrapper.find(AccordionItem).length).toEqual(2);
    });

    it('still renders with no AccordionItemTitle or AccordionItemBody', () => {
        const tree = renderer
            .create(
                <Provider accordionStore={accordionStore}>
                    <AccordionItem>

Fake title

Fake body

                    </AccordionItem>
                </Provider>,
            )
            .toJSON();
        expect(tree).toMatchSnapshot();
    });

    it('still renders with no children at all', () => {
        const tree = renderer
            .create(
                <Provider accordionStore={accordionStore}>
                    <AccordionItem />
                </Provider>,
            )
            .toJSON();
        expect(tree).toMatchSnapshot();
    });

    it('renders with different className', () => {
        const tree = renderer.create(
            <Provider accordionStore={accordionStore}>
                <AccordionItem className="testCSSClass" />
            </Provider>,
        );
        expect(tree.root.findByType('div').props.className).toEqual(
            'testCSSClass',
        );
    });

    it('renders with different hideBodyClassName', () => {
        const tree = renderer.create(
            <Provider accordionStore={accordionStore}>
                <AccordionItem
                    expanded={false}
                    className="accordion-item"
                    hideBodyClassName="accordion-item--hidden"
                />
            </Provider>,
        );
        expect(tree.root.findByType('div').props.className).toEqual(
            'accordion-item accordion-item--hidden',
        );
    });

    it('renders correctly with other blocks inside', () => {
        const tree = renderer
            .create(
                <Provider accordionStore={accordionStore}>
                    <AccordionItem accordion={false}>
                        <AccordionItemTitle>

Fake title

                        </AccordionItemTitle>

Just another block

                        <AccordionItemBody>

Fake body

                        </AccordionItemBody>
                    </AccordionItem>
                </Provider>,
            )
            .toJSON();
        expect(tree).toMatchSnapshot();
    });

    it('renders correctly with other blocks inside 2', () => {
        const tree = renderer
            .create(
                <Provider accordionStore={accordionStore}>
                    <AccordionItem accordion={false}>
                        <AccordionItemTitle>

Fake title

                        </AccordionItemTitle>
                        <AccordionItemBody>

Fake body

                        </AccordionItemBody>

Just another block

                    </AccordionItem>
                </Provider>,
            )
            .toJSON();
        expect(tree).toMatchSnapshot();
    });

    it('can dynamically set expanded prop', () => {
        const Wrapper = ({ expanded }: { expanded: boolean }) => (
            <Provider accordionStore={accordionStore}>
                <AccordionItem expanded={expanded}>
                    <AccordionItemTitle>

Fake title

                    </AccordionItemTitle>
                </AccordionItem>
            </Provider>
        );
        const wrapper = mount(<Wrapper expanded={false} />);
        wrapper.setProps({ expanded: true });

        expect(
            accordionStore.items.filter(item => item.expanded === true).length,
        ).toEqual(1);
    });

    it('can dynamically set activeItems', () => {
        accordionStore.activeItems = ['foo'];
        mount(
            <Provider accordionStore={accordionStore}>
                <AccordionItem itemkey="foo">
                    <AccordionItemTitle>

Fake title

                    </AccordionItemTitle>
                </AccordionItem>
            </Provider>,
        );

        expect(
            accordionStore.items.filter(item => item.expanded === true).length,
        ).toEqual(1);
    });

    it('can dynamically toggle activeItems', () => {
        accordionStore.activeItems = [];
        mount(
            <Provider accordionStore={accordionStore}>
                <AccordionItem itemkey="foo">
                    <AccordionItemTitle>

Fake title

                    </AccordionItemTitle>
                </AccordionItem>
            </Provider>,
        );
        accordionStore.activeItems = ['foo'];

        const fooItem = accordionStore.items.find(
            item => item.itemkey === 'foo',
        );

        expect(fooItem && fooItem.expanded).toEqual(true);
    });
});
<|endoftext|>


<commit_before>// ##View
Patchbay.View = (function() {
  // array of options that will be extended
  // to the view when initialized
  var viewOptions = ['el', 'ui', 'template', 'model', 'data'];

  // `View` constructor returns a View object
  // that contains methods for template/model
  // rendering, dom caching, and event listening.
  var View = Struck.EventObject.extend();

  View.prototype.coreConstructor = function() {
    var self = this;

    Struck.EventObject.prototype.coreConstructor.apply(this, arguments);

    // extend selected instance opitions to object
    _.extend(this, _.pick(this.options, viewOptions));

    // gets model
    this.setModel(this.model, this.data);

    // setup view elements
    this.setElement(result(this.el));

    // render template with model if defined
    this.render(this.model);

    _.defer(function() {
      // cache jquery elements
      self.setUI(self, result(self.ui));

      // run setup function
      self.setup(self.options);
    });
  };

  View.prototype.setModel = function(model, data) {
    data = firstDef(data, {});

    if (model) {
      if (model instanceof Patchbay.Model) {
        this.model = model;
        this.model.set(data);
      } else if (typeof model === 'function' && !!model.create) {
        this.model = model.create(data);
      } else if (typeof model === 'object') {
        this.model = Patchbay.Model.create(model);
      }
    } else {
      this.model = Patchbay.Model.create(data);
    }
  };

  // caches the dom object and creates scoped find function
  View.prototype.setElement = function(el) {
    if (el) {
      this.$el = $(el).eq(0);
      this.el = this.$el[0];
      this.$ = function(el) {
        return this.$el.find(el);
      };
    }
  };

  View.prototype.setUI = function(ui) {
    // cache dom objects from UI object
    this.ui = _.reduce(ui, function(result, selector, name) {
      result[name] = this.$(selector);
      return result;
    }, {}, this);
  };

  // `render` function that runs
  // template function with model data
  View.prototype.render = Struck.hook('render', function(template, model) {
    if(_.isUndefined(template)) {
      return;
    }

    if (_.isFunction(template)) {
      this.setElement(template(firstDef(model.data, {})));
    } else if (_.isString(template)) {
      this.setElement(_.template(template, firstDef(model.data, {})));
    }
  });

  // overwritable `setup` function
  // called when View is initialized
  View.prototype.setup = _.noop;

  // overwritable `destroy` function
  // that should be called when removing
  // a view to remove event listeners
  // or any possible memory leaks
  View.prototype.destroy = function() {
    Struck.EventObject.prototype.destroy.apply(this, arguments);

    // destroy model from view
    this.model.destroy();
  };

  // ###Private Functions

  return View;
});<commit_msg>changes constructor<commit_after>// ##View
Patchbay.View = (function() {
  // array of options that will be extended
  // to the view when initialized
  var viewOptions = ['el', 'ui', 'template', 'model', 'data'];

  // `View` constructor returns a View object
  // that contains methods for template/model
  // rendering, dom caching, and event listening.
  var View = Struck.EventObject.extend();

  View.prototype.baseConstructor = function() {
    var self = this;

    Struck.EventObject.prototype.baseConstructor.apply(this, arguments);

    // extend selected instance opitions to object
    _.extend(this, _.pick(this.options, viewOptions));

    // gets model
    this.setModel(this.model, this.data);

    // setup view elements
    this.setElement(result(this.el));

    // render template with model if defined
    this.render(this.model);

    _.defer(function() {
      // cache jquery elements
      self.setUI(self, result(self.ui));

      // run setup function
      self.setup(self.options);
    });
  };

  View.prototype.setModel = function(model, data) {
    data = firstDef(data, {});

    if (model) {
      if (model instanceof Patchbay.Model) {
        this.model = model;
        this.model.set(data);
      } else if (typeof model === 'function' && !!model.create) {
        this.model = model.create(data);
      } else if (typeof model === 'object') {
        this.model = Patchbay.Model.create(model);
      }
    } else {
      this.model = Patchbay.Model.create(data);
    }
  };

  // caches the dom object and creates scoped find function
  View.prototype.setElement = function(el) {
    if (el) {
      this.$el = $(el).eq(0);
      this.el = this.$el[0];
      this.$ = function(el) {
        return this.$el.find(el);
      };
    }
  };

  View.prototype.setUI = function(ui) {
    // cache dom objects from UI object
    this.ui = _.reduce(ui, function(result, selector, name) {
      result[name] = this.$(selector);
      return result;
    }, {}, this);
  };

  // `render` function that runs
  // template function with model data
  View.prototype.render = Struck.hook('render', function(template, model) {
    if(_.isUndefined(template)) {
      return;
    }

    if (_.isFunction(template)) {
      this.setElement(template(firstDef(model.data, {})));
    } else if (_.isString(template)) {
      this.setElement(_.template(template, firstDef(model.data, {})));
    }
  });

  // overwritable `setup` function
  // called when View is initialized
  View.prototype.setup = _.noop;

  // overwritable `destroys` function
  // that should be called when removing
  // a view to remove event listeners
  // or any possible memory leaks
  View.prototype.destroy = function() {
    Struck.EventObject.prototype.destroy.apply(this, arguments);

    // destroy model from view
    this.model.destroy();
  };

  return View;
});<|endoftext|>


<commit_before>import { app } from '@mindhive/di'
import withStyles from '../../theme/withStyles'
import { trans as transitions } from '../../styles/animations'
import { observer } from 'mobx-react'

export default ({
  palette,
  colorManipulator,
  typography,
  spacing,

  drawer,
}) => ({
  drawer: {
    expandedWidth: drawer.width,
    narrowWidth: spacing.desktopDrawerMenuItemHeight + 8,
    backgroundColor: palette.darkSecondary1Color,
    menuItem: {
      color: palette.secondary1Color,
      fontWeight: typography.fontWeight100,
      fontSize: 18,
    },
    active: {
      fontWeight: typography.fontWeight700,
    },
    activeIcon: {
      color: 'white',
      // color: colorManipulator.lighten(palette.primary1Color, 0.4),
      transition: transitions.cubicAll,
      transform: 'scale(1.5, 1.5) translate(1px, 1px)',
    },
    divider: {
      zIndex: 10000,
      backgroundColor: colorManipulator.darken(palette.darkSecondary1Color, 0.5),
    },
    docked: {
      top: spacing.desktopKeylineIncrement,
    },
  },
})

const mapThemeToStyles = ({
  colorManipulator,
  appBar,
  drawer,
},
  {
    active,
    hovered,
    menuItemHovered,
    hideWhenExpanded,
    hideWhenNarrow,
    inject: { navDrawerDomain: domain, layoutDomain } = app(),
  }
) => {
  const menuItemRootStyles = {
    backgroundColor: hovered ? colorManipulator.darken(drawer.backgroundColor, 0.1) : drawer.backgroundColor,
  }
  const showing = domain.expanded || hovered
  const translateDistance = domain.expanded ? drawer.expandedWidth : drawer.narrowWidth
  const transform = domain.docked || domain.open ? 'translate(0, 0)' : `translate(-${translateDistance}px, 0)`
  const topOffset = layoutDomain.topOffset
  return ({
    expandVisible: {
      transition: transitions.cubicAll,
      opacity: domain.expanded ? (hideWhenExpanded ? 0 : 1) : (hideWhenNarrow ? 0 : 1),
    },
    drawer: {
      position: 'fixed',
      left: 0,
      top: 0,
      width: domain.expanded ? drawer.expandedWidth : drawer.narrowWidth,
      backgroundColor: drawer.backgroundColor,
      height: `calc(100% - ${topOffset}px)`,
      marginTop: topOffset,
      // left: domain.open || domain.docked ? 0 : -drawer.expandedWidth,
      transition: transitions.cubicAll,
      transform,
    },
    divider: drawer.divider,
    menuItem: menuItemRootStyles,
    icon: {
      ...drawer.menuItem,
      ...(active ? drawer.activeIcon : {}),
      transform: `translate(3px, 3px) ${active ? drawer.activeIcon.transform : ''}`,
    },
    subIcon: isActive => ({
      ...drawer.menuItem,
      ...(isActive ? drawer.activeIcon : {}),
      transform: `translate(3px, 3px) ${isActive ? drawer.activeIcon.transform : ''}`,
    }),
    menuLabel: {
      container: {
        display: 'inline-block',
      },
    },
    menuItemFlyOut: {
      container: {
        position: domain.isFixedWidth ? 'relative' : 'fixed',
        zIndex: 1390,
        ...drawer.menuItem,
        ...menuItemRootStyles,
        overflow: 'hidden',
        left: 0,
        transition: `${transitions.cubicAll}, top 0s`,
        transform,
        width: showing ? drawer.expandedWidth : drawer.narrowWidth,
        ...(active ? drawer.active : {}),
      },
      subMenu: {
        paddingLeft: showing ? 24 : 0,
        zIndex: 1390,
      },
      inner: {
      },
    },
    rowItem: {},
    expandedBtn: {
      position: 'relative',
      left: domain.expanded ? drawer.width - 64 : -16,
      transform: `rotate(${domain.expanded ? -180 : 0}deg)`,
    },
    expandedIcon: {
      ...drawer.menuItem,
    },
  })
}

export const injectStylesSheet = Component =>
  observer(withStyles(mapThemeToStyles)(Component))

<commit_msg>AppDrawer Theme<commit_after>import { app } from '@mindhive/di'
import withStyles from '../../theme/withStyles'
import { trans as transitions } from '../../styles/animations'
import { observer } from 'mobx-react'

export default ({
  palette,
  colorManipulator,
  typography,
  spacing,

  drawer,
}) => ({
  drawer: {
    expandedWidth: drawer.width,
    narrowWidth: spacing.desktopDrawerMenuItemHeight + 8,
    backgroundColor: palette.darkSecondary1Color,
    menuItem: {
      color: palette.secondary1Color,
      fontWeight: typography.fontWeight100,
      fontSize: 18,
    },
    active: {
      fontWeight: typography.fontWeight700,
    },
    activeIcon: {
      color: 'white',
      // color: colorManipulator.lighten(palette.primary1Color, 0.4),
      transition: transitions.cubicAll,
      transform: 'scale(1.5, 1.5) translate(1px, 1px)',
    },
    divider: {
      zIndex: 10000,
      backgroundColor: colorManipulator.darken(palette.darkSecondary1Color, 0.5),
    },
    docked: {
      top: spacing.desktopKeylineIncrement,
    },
  },
})

const mapThemeToStyles = ({
  colorManipulator,
  appBar,
  drawer,
  appDrawer = {
    menuItem: {},
  },
},
  {
    active,
    hovered,
    menuItemHovered,
    hideWhenExpanded,
    hideWhenNarrow,
    inject: { navDrawerDomain: domain, layoutDomain } = app(),
  }
) => {
  const drawerBackgroundColor = appDrawer.backgroundColor || drawer.backgroundColor
  const hoveredBackgroundColor = appDrawer.hoveredBackgroundColor || colorManipulator.darken(drawerBackgroundColor, 0.1)
  const drawerMenuItem =  Object.assign({}, drawer.menuItem, appDrawer.menuItem)
  const drawerActiveIcon =  Object.assign({}, drawer.activeIcon, appDrawer.activeIcon || {})
  const drawerActiveMenuItem =  Object.assign({}, drawer.active, appDrawer.active || {})

  const menuItemRootStyles = {
    backgroundColor: hovered ? hoveredBackgroundColor : appDrawer.menuItem.backgroundColor || drawerBackgroundColor,
  }
  const showing = domain.expanded || hovered
  const translateDistance = domain.expanded ? drawer.expandedWidth : drawer.narrowWidth
  const transform = domain.docked || domain.open ? 'translate(0, 0)' : `translate(-${translateDistance}px, 0)`
  const topOffset = layoutDomain.topOffset
  return ({
    expandVisible: {
      transition: transitions.cubicAll,
      opacity: domain.expanded ? (hideWhenExpanded ? 0 : 1) : (hideWhenNarrow ? 0 : 1),
    },
    drawer: {
      position: 'fixed',
      left: 0,
      top: 0,
      width: domain.expanded ? drawer.expandedWidth : drawer.narrowWidth,
      backgroundColor: drawerBackgroundColor,
      height: `calc(100% - ${topOffset}px)`,
      marginTop: topOffset,
      // left: domain.open || domain.docked ? 0 : -drawer.expandedWidth,
      transition: transitions.cubicAll,
      transform,
    },
    divider: drawer.divider,
    menuItem: menuItemRootStyles,
    icon: {
      ...drawerMenuItem,
      ...(active ? drawerActiveIcon : {}),
      transform: `translate(3px, 3px) ${active ? drawerActiveIcon.transform : ''}`,
    },
    subIcon: isActive => ({
      ...drawerMenuItem,
      ...(isActive ? drawerActiveIcon : {}),
      transform: `translate(3px, 3px) ${isActive ? drawerActiveIcon.transform : ''}`,
    }),
    menuLabel: {
      container: {
        display: 'inline-block',
      },
    },
    menuItemFlyOut: {
      container: {
        position: domain.isFixedWidth ? 'relative' : 'fixed',
        zIndex: 1390,
        ...drawerMenuItem,
        ...menuItemRootStyles,
        overflow: 'hidden',
        left: 0,
        transition: `${transitions.cubicAll}, top 0s`,
        transform,
        width: showing ? drawer.expandedWidth : drawer.narrowWidth,
        ...(active ? drawerActiveMenuItem : {}),
      },
      subMenu: {
        paddingLeft: showing ? 24 : 0,
        zIndex: 1390,
      },
      inner: {

      },
    },
    rowItem: {},
    expandedBtn: {
      position: 'relative',
      left: domain.expanded ? drawer.width - 64 : -16,
      transform: `rotate(${domain.expanded ? -180 : 0}deg)`,
    },
    expandedIcon: {
      ...drawerMenuItem,
    },
  })
}

export const injectStylesSheet = Component =>
  observer(withStyles(mapThemeToStyles)(Component))

<|endoftext|>


<commit_before>/**
 * @fileoverview A libary for working with SharePoint lists via the SharePoint
 * REST API. Supports reading, updating and deleting list items, as well as a
 * few extra functions such as getting a list of all columns in a SP list.
 */

/**
 * Initializes a new instance of the SpRestApi class, which contains methods
 * for calling the SharePoint REST API.
 * @class SpRestApi
 * @typedef {Object} SpRestApi
 * @constructor
 * @param {SpRestApiOptions} [options] - The optional settings to override the
 *      defaults.
 */
var SpRestApi = function (options) {
    /**
     * The default options that will be used unless overridden.
     * @type {SpRestApiOptions}
     */
    this.defaultOptions = {
        onsuccess: console.log,
        onerror: console.log,
        listTitle: '',
        maxItems: 100,
        recursiveFetch: true,
        verbosity: SpRestApi.Verbosity.VERBOSE,
        siteUrl: _spPageContextInfo ? _spPageContextInfo.webAbsoluteUrl : '',
        token: document.getElementById("__REQUESTDIGEST") ?
            document.getElementById("__REQUESTDIGEST").value : '',
        urls: {
            list: '/_api/web/lists/getbytitle(\'{0}\')/items',
            item: '/_api/web/lists/getbytitle(\'{0}\')/items({1})',
        },
    };

    this.options = $.extend(this.defaultOptions, options);
};

/**
 * Determines the amount of metadata in the response JSON from server.
 * For most cases, 'COMPACT' should be enough.
 * @readonly
 * @enum {string}
 * @typedef Verbosity
 */
SpRestApi.Verbosity = {
    /** Values are placed in `.value`. Less metadata.
        Not supported in SP 2013 and earlier. */
    COMPACT: 'application/json;odata=nometadata',

    /** Value are placed in `.value`. Moderate metadata.
        Not supported in SP 2013 and earlier. */
    MINIMAL: 'application/json;odata=minimalmetadata',

    /** Values are placed in `.d.results`. More metadata. */
    VERBOSE: 'application/json;odata=verbose',
};

/**
 * @typedef {Object} SpRestApiOptions - The options passed to methods
 *      inside the SpRestApi class.
 * @property {Array.<SpRestApiFilterCriterion>} filters - The filters to be
 *      used in filtering the list items using the $filter parameter.
 * @property {string} [token] - The SharePoint's request digest, a token that
 *      it is required for every API call. Required only if using outside a
 *      SharePoint page, otherwise it is obtained automatically from DOM.
 * @property {Function} [onsuccess] - The callback function for successful
 *      requests to SharePoint REST API.
 * @property {Function} [onerror] - The callback function for failed requests
 *      to SharePoint REST API.
 * @property {string} [listTitle] - The display name of the SharePoint list.
 * @property {number} [maxItems] - The maximum number of items to be returned
 *      from the list. If `recursiveFetch` is set to true, this is the
 *      maximum number of items to fetch on each request to server. If not
 *      not specified, defaults to SharePoint's limit of 100. Maximum is
 *      5000 due to SharePoint limitations.
 * @property {boolean} [recursiveFetch] - Fetch all items from the list by
 *      repeatedly making server requests until all list items are fetched.
 *      This is to overcome SharePoint's limitation of maximum 5000 items
 *      per call.
 * @property {Verbosity} [verbosity] - The amount of metadata to be returned
 *      in the JSON response from server. Use the SpRestApi.Verbosity enum.
 * @property {string} [siteUrl] - The SharePoint site URL which is usually
 *      obtained from the _spPageContextInfo.webAbsoluteUrl. Required if using
 *      this library outside of a SharePoint page.
 * @property {Array.<string>} [urls] - The URLs of various API calls, e.g. to
 *      get a list item, all items in a list etc.
 */
/**
 * Stores this instance's options.
 * @type {SpRestApiOptions}
 */
SpRestApi.prototype.options = {};

/**
 * Array of cached SharePoint list items. Stores the data during the recursive
 * fetch (options.recursiveFetch = true), and is cleared immediately when the
 * recursive fetch completes.
 * @type {Array.<Object>}
 */
SpRestApi.prototype.cachedListItems = [];

/**
 * Sets the list title (list display name) of this SpRestApi instance.
 * The .lists() must be called before any call to other list-related
 * methods.
 * @param {string} listTitle - The display name of the SharePoint list.
 * @returns {SpRestApi} Returns the instance of this SpRestApi object.
 */
SpRestApi.prototype.lists = function (listTitle) {
    this.options.listTitle = listTitle;
    return this;
};

/**
 * Sets the SpRestApiOptions. If not called, before the request to server,
 * the default options will be used.
 * @param {SpRestApiOptions} options - The partial SpRestApiOptions object,
 *      where each field will override a default setting in `.defaultOptions`.
 * @returns {SpRestApi} This SpRestApi instance.
 */
SpRestApi.prototype.config = function (options) {
    // Merge the specified options with the default options
    this.options = $.extend(this.defaultOptions, options);
    return this;
};

/**
 * Adds the $top= string to the specified URL, to limit the max number of
 * items in the response.
 * @param {string} url - the URL to add the $top string to.
 * @returns {string} The URL with the added "?"/"&" character and the $top=
 *      URL parameter.
 */
SpRestApi.prototype.addMaxItems = function (url) {
    // Add '?' or '&' to URL query string
    url += url.includes('?') ? '&' : '?';

    return url + "$top=" + this.options.maxItems;
};

/**
 * Returns all items from a list, or all items up to the SharePoint limit
 * or the limit specified in the options.
 */
SpRestApi.prototype.getAllItems = function () {
    var url = this.generateGetAllListItemsUrl();

    var onsuccess;
    if (this.options.recursiveFetch) {
        // Continue fetching items recursively until we load the entire list:
        onsuccess = this.continueRecursiveFetch;
    } else {
        onsuccess = this.options.onsuccess;
    }

    this.loadUrl(url, 'GET', onsuccess, this.options.onerror);
};

/**
 * Generates the URL for fetching all items from a list. Uses in getAllItems()
 * and in getAllItemsFromSubfolder().
 * @returns {string} The SP API URL for fetching all items from a list.
 */
SpRestApi.prototype.generateGetAllListItemsUrl = function () {
    var url = this.options.siteUrl +
        this.options.urls.list.format(this.options.listTitle);
    url = this.addMaxItems(url);
    return url;
};

/**
 * Returns all list items from a subfolder of a SharePoint list. Uses a hacky
 * way - by matching a substring of the FileRef, to avoid relying on CAML.
 * @param {string} subfolderName - The display name of the subfolder in a list.
 *      Must not include any slashes.
 */
SpRestApi.prototype.getAllItemsFromListSubfolder = function (subfolderName) {
    // The idea here is that if the FileRef property of a list item is
    // like this - /sites/mysite/Lists/My List/My Subfolder/123_.000 -
    // then we can filter the list by FileRef containing the
    // string 'Lists/My List/My Subfolder'.
    var fileref = 'Lists/' +
        this.options.listTitle + '/' + subfolderName + '/';

    var url = this.generateGetAllListItemsUrl();
    url += '&$filter=substringof(\'' + fileref + '\', FileRef)';

    var onsuccess;
    if (this.options.recursiveFetch) {
        // Continue fetching items recursively until we load the entire list:
        onsuccess = this.continueRecursiveFetch;
    } else {
        onsuccess = this.options.onsuccess;
    }

    this.loadUrl(url, 'GET', onsuccess, this.options.onerror);
};

/**
 * Keeps loading data recursively until all list items are obtained. This is
 * to overcome SharePoint's limitation on the number of list items per query.
 */
SpRestApi.prototype.continueRecursiveFetch = function (data) {
    var newData;
    var nextUrl;

    // Depending on the Verbosity setting, the data will be returned in
    // significantly different formats (inside data.d.results or data.value).
    if (this.options.verbosity === SpRestApi.Verbosity.VERBOSE) {
        newData = data.d.results;
        nextUrl = data.d.__next;
    } else {
        newData = data.value;
        nextUrl = data['odata.nextLink']; // dot in property name
    }

    this.cachedListItems = this.cachedListItems.concat(newData);

    if (nextUrl) {
        // While next URL is not empty, keep loading recursively:
        this.loadUrl(nextUrl, 'GET',
            this.continueRecursiveFetch, this.options.onerror);
    } else {
        // Load complete - generate a structure similar to server response,
        // and call the callback.
        var entireData;
        if (this.options.verbosity === SpRestApi.Verbosity.VERBOSE) {
            entireData = {
                d: {
                    results: this.cachedListItems
                }
            };
        } else {
            entireData = {
                value: this.cachedListItems
            };
        }

        this.options.success(entireData);
    }
};

/**
 * Returns a single item from a list.
 * @param {number} itemId - The SharePoint list item ID of the item we need to
 *      fetch.
 */
SpRestApi.prototype.getItem = function (itemId) {
    if (!itemId) { throw "The list item ID must not be empty."; }

    var url = this.options.siteUrl +
        this.options.urls.item.format(this.options.listTitle, itemId);
    this.loadUrl(url, 'GET', this.options.onsuccess, this.options.onerror);
};

/**
 * A generic function to call any URL of the SharePoint REST API. Usually
 * there is no need to call this method directly.
 * @param {string} url - The URL of the SharePoint REST API to be queried. Will
 *      not be modified by this method.
 * @param {string} method - HTTP method for this request, e.g. 'GET', 'POST',
 *      'DELETE'.
 * @param {Function} success - Callback for successfull REST API call.
 * @param {Function} error - Callback for failed REST API call.
 */
SpRestApi.prototype.loadUrl = function (url, method, success, error) {
    // Preserve `this` containing the current instance of SpRestApi.
    var $ajax = $.proxy($.ajax, this);

    $ajax({
        url: url,
        type: method,
        cache: false,
        contentType: this.options.verbosity,
        headers: {
            "Accept": this.options.verbosity,
            "X-RequestDigest": this.options.token,
        },
        success: function (data) {
            success(data);
        },
        error: function (data) {
            error(data);
        },
    });
};

/**
 * Sends a request to SharePoint to get the SharePoint authorization token,
 * which is required for all data requests. This is necessary in two cases:
 * - We are loading this script from a non-SharePoint page (e.g. normal HTML);
 * - We are refreshing the token (which expires after 30 minutes).
 * @param {Function} callback - The callback to run after the authorization
 *      token is received successfully.
 */
SpRestApi.prototype.refreshDigest = function (callback) {
    var url = this.siteUrl + '/_api/contextinfo';

    // If request succeeded:
    var success = function (data) {
        if (data && data.d && data.d.GetContextWebInformation &&
            data.d.GetContextWebInformation.FormDigestValue) {
            // If Verbosity = odata=verbose:
            this.options = data.d.GetContextWebInformation.FormDigestValue;

        } else if (data && data.value && data.value.GetContextWebInformation &&
            data.value.GetContextWebInformation.FormDigestValue) { // TODO FIXME need to verify this path is correct in SP online
            // If Verbosity = odata=nometadata, odata=minimalmetadata:
            this.options = data.value.GetContextWebInformation.FormDigestValue;
        } else {
            throw 'Unable to obtain SharePoint authorization token.';
        }

        if (typeof callback === 'function') {
            callback();
        }
    };

    // If request failed:
    var error = function () {
        throw 'Unable to obtain SharePoint authorization token';
    };

    this.loadUrl(url, 'POST', success, error);
};

/* Polyfills
-----------------------------*/

if (!String.prototype.format) {
    /**
    * Replaces symbols like {0}, {1} in a string with the values from
    * the arguments.
    * @returns {string} The string with the replaced placeholders.
    */
    String.prototype.format = function () {
        var args = arguments;
        return this.replace(/{(\d+)}/g, function (match, number) {
            return typeof args[number] !== 'undefined'
                ? args[number]
                : match
                ;
        });
    };
}

if (!String.prototype.includes) {
    String.prototype.includes = function (search, start) {
        'use strict';
        if (typeof start !== 'number') {
            start = 0;
        }

        if (start + search.length > this.length) {
            return false;
        } else {
            return this.indexOf(search, start) !== -1;
        }
    };
}<commit_msg>start implementing delete item - move URL generation into separate function<commit_after>/**
 * @fileoverview A libary for working with SharePoint lists via the SharePoint
 * REST API. Supports reading, updating and deleting list items, as well as a
 * few extra functions such as getting a list of all columns in a SP list.
 */

/**
 * Initializes a new instance of the SpRestApi class, which contains methods
 * for calling the SharePoint REST API.
 * @class SpRestApi
 * @typedef {Object} SpRestApi
 * @constructor
 * @param {SpRestApiOptions} [options] - The optional settings to override the
 *      defaults.
 */
var SpRestApi = function (options) {
    /**
     * The default options that will be used unless overridden.
     * @type {SpRestApiOptions}
     */
    this.defaultOptions = {
        onsuccess: console.log,
        onerror: console.log,
        listTitle: '',
        maxItems: 100,
        recursiveFetch: true,
        verbosity: SpRestApi.Verbosity.VERBOSE,
        siteUrl: _spPageContextInfo ? _spPageContextInfo.webAbsoluteUrl : '',
        token: document.getElementById("__REQUESTDIGEST") ?
            document.getElementById("__REQUESTDIGEST").value : '',
        urls: {
            list: '/_api/web/lists/getbytitle(\'{0}\')/items',
            item: '/_api/web/lists/getbytitle(\'{0}\')/items({1})',
        },
    };

    this.options = $.extend(this.defaultOptions, options);
};

/**
 * Determines the amount of metadata in the response JSON from server.
 * For most cases, 'COMPACT' should be enough.
 * @readonly
 * @enum {string}
 * @typedef Verbosity
 */
SpRestApi.Verbosity = {
    /** Values are placed in `.value`. Less metadata.
        Not supported in SP 2013 and earlier. */
    COMPACT: 'application/json;odata=nometadata',

    /** Value are placed in `.value`. Moderate metadata.
        Not supported in SP 2013 and earlier. */
    MINIMAL: 'application/json;odata=minimalmetadata',

    /** Values are placed in `.d.results`. More metadata. */
    VERBOSE: 'application/json;odata=verbose',
};

/**
 * @typedef {Object} SpRestApiOptions - The options passed to methods
 *      inside the SpRestApi class.
 * @property {Array.<SpRestApiFilterCriterion>} filters - The filters to be
 *      used in filtering the list items using the $filter parameter.
 * @property {string} [token] - The SharePoint's request digest, a token that
 *      it is required for every API call. Required only if using outside a
 *      SharePoint page, otherwise it is obtained automatically from DOM.
 * @property {Function} [onsuccess] - The callback function for successful
 *      requests to SharePoint REST API.
 * @property {Function} [onerror] - The callback function for failed requests
 *      to SharePoint REST API.
 * @property {string} [listTitle] - The display name of the SharePoint list.
 * @property {number} [maxItems] - The maximum number of items to be returned
 *      from the list. If `recursiveFetch` is set to true, this is the
 *      maximum number of items to fetch on each request to server. If not
 *      not specified, defaults to SharePoint's limit of 100. Maximum is
 *      5000 due to SharePoint limitations.
 * @property {boolean} [recursiveFetch] - Fetch all items from the list by
 *      repeatedly making server requests until all list items are fetched.
 *      This is to overcome SharePoint's limitation of maximum 5000 items
 *      per call.
 * @property {Verbosity} [verbosity] - The amount of metadata to be returned
 *      in the JSON response from server. Use the SpRestApi.Verbosity enum.
 * @property {string} [siteUrl] - The SharePoint site URL which is usually
 *      obtained from the _spPageContextInfo.webAbsoluteUrl. Required if using
 *      this library outside of a SharePoint page.
 * @property {Array.<string>} [urls] - The URLs of various API calls, e.g. to
 *      get a list item, all items in a list etc.
 */
/**
 * Stores this instance's options.
 * @type {SpRestApiOptions}
 */
SpRestApi.prototype.options = {};

/**
 * Array of cached SharePoint list items. Stores the data during the recursive
 * fetch (options.recursiveFetch = true), and is cleared immediately when the
 * recursive fetch completes.
 * @type {Array.<Object>}
 */
SpRestApi.prototype.cachedListItems = [];

/**
 * Sets the list title (list display name) of this SpRestApi instance.
 * The .lists() must be called before any call to other list-related
 * methods.
 * @param {string} listTitle - The display name of the SharePoint list.
 * @returns {SpRestApi} Returns the instance of this SpRestApi object.
 */
SpRestApi.prototype.lists = function (listTitle) {
    this.options.listTitle = listTitle;
    return this;
};

/**
 * Sets the SpRestApiOptions. If not called, before the request to server,
 * the default options will be used.
 * @param {SpRestApiOptions} options - The partial SpRestApiOptions object,
 *      where each field will override a default setting in `.defaultOptions`.
 * @returns {SpRestApi} This SpRestApi instance.
 */
SpRestApi.prototype.config = function (options) {
    // Merge the specified options with the default options
    this.options = $.extend(this.defaultOptions, options);
    return this;
};

/**
 * Adds the $top= string to the specified URL, to limit the max number of
 * items in the response.
 * @param {string} url - the URL to add the $top string to.
 * @returns {string} The URL with the added "?"/"&" character and the $top=
 *      URL parameter.
 */
SpRestApi.prototype.addMaxItems = function (url) {
    // Add '?' or '&' to URL query string
    url += url.includes('?') ? '&' : '?';

    return url + "$top=" + this.options.maxItems;
};

/**
 * Returns all items from a list, or all items up to the SharePoint limit
 * or the limit specified in the options.
 */
SpRestApi.prototype.getAllItems = function () {
    var url = this.generateGetAllListItemsUrl();

    var onsuccess;
    if (this.options.recursiveFetch) {
        // Continue fetching items recursively until we load the entire list:
        onsuccess = this.continueRecursiveFetch;
    } else {
        onsuccess = this.options.onsuccess;
    }

    this.loadUrl(url, 'GET', onsuccess, this.options.onerror);
};

/**
 * Generates the URL for fetching all items from a list. Uses in getAllItems()
 * and in getAllItemsFromSubfolder().
 * @returns {string} The SP API URL for fetching all items from a list.
 */
SpRestApi.prototype.generateGetAllListItemsUrl = function () {
    var url = this.options.siteUrl +
        this.options.urls.list.format(this.options.listTitle);
    url = this.addMaxItems(url);
    return url;
};

/**
 * Generates the URL for getting or deleting a single list item.
 * @param {number} itemId - The list item ID of the item to be deleted.
 * @returns {string} An URL ending with e.g. /Lists('MyList')/Items(761)
 */
SpRestApi.prototype.generateSingleListItemUrl = function (itemId) {
    return this.options.siteUrl +
        this.options.urls.item.format(this.options.listTitle, itemId);
}

/**
 * Returns all list items from a subfolder of a SharePoint list. Uses a hacky
 * way - by matching a substring of the FileRef, to avoid relying on CAML.
 * @param {string} subfolderName - The display name of the subfolder in a list.
 *      Must not include any slashes.
 */
SpRestApi.prototype.getAllItemsFromListSubfolder = function (subfolderName) {
    // The idea here is that if the FileRef property of a list item is
    // like this - /sites/mysite/Lists/My List/My Subfolder/123_.000 -
    // then we can filter the list by FileRef containing the
    // string 'Lists/My List/My Subfolder'.
    var fileref = 'Lists/' +
        this.options.listTitle + '/' + subfolderName + '/';

    var url = this.generateGetAllListItemsUrl();
    url += '&$filter=substringof(\'' + fileref + '\', FileRef)';

    var onsuccess;
    if (this.options.recursiveFetch) {
        // Continue fetching items recursively until we load the entire list:
        onsuccess = this.continueRecursiveFetch;
    } else {
        onsuccess = this.options.onsuccess;
    }

    this.loadUrl(url, 'GET', onsuccess, this.options.onerror);
};

/**
 * Keeps loading data recursively until all list items are obtained. This is
 * to overcome SharePoint's limitation on the number of list items per query.
 */
SpRestApi.prototype.continueRecursiveFetch = function (data) {
    var newData;
    var nextUrl;

    // Depending on the Verbosity setting, the data will be returned in
    // significantly different formats (inside data.d.results or data.value).
    if (this.options.verbosity === SpRestApi.Verbosity.VERBOSE) {
        newData = data.d.results;
        nextUrl = data.d.__next;
    } else {
        newData = data.value;
        nextUrl = data['odata.nextLink']; // dot in property name
    }

    this.cachedListItems = this.cachedListItems.concat(newData);

    if (nextUrl) {
        // While next URL is not empty, keep loading recursively:
        this.loadUrl(nextUrl, 'GET',
            this.continueRecursiveFetch, this.options.onerror);
    } else {
        // Load complete - generate a structure similar to server response,
        // and call the callback.
        var entireData;
        if (this.options.verbosity === SpRestApi.Verbosity.VERBOSE) {
            entireData = {
                d: {
                    results: this.cachedListItems
                }
            };
        } else {
            entireData = {
                value: this.cachedListItems
            };
        }

        this.options.success(entireData);
    }
};

/**
 * Returns a single item from a list.
 * @param {number} itemId - The SharePoint list item ID of the item we need to
 *      fetch.
 */
SpRestApi.prototype.getItem = function (itemId) {
    if (!itemId) { throw "The list item ID must not be empty."; }

    var url = this.options.siteUrl +
        this.options.urls.item.format(this.options.listTitle, itemId);
    this.loadUrl(url, 'GET', this.options.onsuccess, this.options.onerror);
};

/**
 * Deletes a single item from a SharePoint list.
 * @type {number} itemId - The SharePoint list item ID of the item to be
 *      deleted.
 */
SpRestApi.prototype.deleteItem = function (itemId) {
    var url =
};

/**
 * A generic function to call any URL of the SharePoint REST API. Usually
 * there is no need to call this method directly.
 * @param {string} url - The URL of the SharePoint REST API to be queried. Will
 *      not be modified by this method.
 * @param {string} method - HTTP method for this request, e.g. 'GET', 'POST',
 *      'DELETE'.
 * @param {Function} success - Callback for successfull REST API call.
 * @param {Function} error - Callback for failed REST API call.
 */
SpRestApi.prototype.loadUrl = function (url, method, success, error) {
    // Preserve `this` containing the current instance of SpRestApi.
    var $ajax = $.proxy($.ajax, this);

    // These headers are common for all requests
    var headers = {
        "Accept": this.options.verbosity,
        "X-RequestDigest": this.options.token,
    };

    // For the DELETE method, we actually send the request as POST
    if (method === 'DELETE') {
        headers['IF-MATCH'] = '*';
        headers["X-HTTP-METHOD"] = 'DELETE';
        method = 'POST';
    }

    $ajax({
        url: url,
        type: method,
        cache: false,
        contentType: this.options.verbosity,
        headers: headers,
        success: function (data) {
            success(data);
        },
        error: function (data) {
            error(data);
        },
    });
};

/**
 * Sends a request to SharePoint to get the SharePoint authorization token,
 * which is required for all data requests. This is necessary in two cases:
 * - We are loading this script from a non-SharePoint page (e.g. normal HTML);
 * - We are refreshing the token (which expires after 30 minutes).
 * @param {Function} callback - The callback to run after the authorization
 *      token is received successfully.
 */
SpRestApi.prototype.refreshDigest = function (callback) {
    var url = this.siteUrl + '/_api/contextinfo';

    // If request succeeded:
    var success = function (data) {
        if (data && data.d && data.d.GetContextWebInformation &&
            data.d.GetContextWebInformation.FormDigestValue) {
            // If Verbosity = odata=verbose:
            this.options = data.d.GetContextWebInformation.FormDigestValue;

        } else if (data && data.value && data.value.GetContextWebInformation &&
            data.value.GetContextWebInformation.FormDigestValue) { // TODO FIXME need to verify this path is correct in SP online
            // If Verbosity = odata=nometadata, odata=minimalmetadata:
            this.options = data.value.GetContextWebInformation.FormDigestValue;
        } else {
            throw 'Unable to obtain SharePoint authorization token.';
        }

        if (typeof callback === 'function') {
            callback();
        }
    };

    // If request failed:
    var error = function () {
        throw 'Unable to obtain SharePoint authorization token';
    };

    this.loadUrl(url, 'POST', success, error);
};

/* Polyfills
-----------------------------*/

if (!String.prototype.format) {
    /**
    * Replaces symbols like {0}, {1} in a string with the values from
    * the arguments.
    * @returns {string} The string with the replaced placeholders.
    */
    String.prototype.format = function () {
        var args = arguments;
        return this.replace(/{(\d+)}/g, function (match, number) {
            return typeof args[number] !== 'undefined'
                ? args[number]
                : match
                ;
        });
    };
}

if (!String.prototype.includes) {
    String.prototype.includes = function (search, start) {
        'use strict';
        if (typeof start !== 'number') {
            start = 0;
        }

        if (start + search.length > this.length) {
            return false;
        } else {
            return this.indexOf(search, start) !== -1;
        }
    };
}<|endoftext|>


<commit_before>
var app = angular.module('ngPortalApp', ['ngRoute', 'ngMaterial']);
app.config(function($routeProvider, $locationProvider, $httpProvider,$controllerProvider) {
    app.controller = function (name, controller) {
        $controllerProvider.register(name, controller);
    };

    $httpProvider.interceptors.push(function($q, $location) {
        return {
            'request': function(config) {

                config.headers['X-Requested-With'] = 'XMLHttpRequest'
                UIR.load.show('Cargando....')
                return config;
            },
            'responseError': function(rejection) {

                UIR.load.hide()
                if (!rejection.config.ignoreRequest && rejection.status == 404)
                    $location.path('/404')
                if (!rejection.config.ignoreRequest && rejection.status == 401) {
                    UIR.load.show('Autenticación detectada, redireccionando....')
                    window.location.href = '/'+Raptor.ngPortal.route+'/home'
                    return;
                }

                return $q.reject(rejection);
            },
            'response': function(response) {
                // same as above
                UIR.load.hide()
                return response;
            }
        };
    });

    $routeProvider
            .when('/',{redirectTo: '/e/'+Raptor.ngPortal.route+'/home/description'})
            .when("/e/:path*", {
                templateUrl: function(params) {
                    return "/" + params.path+ "?t=" + Date.now()
                },
                controller: "EmbededController"
            })
            .when("/f/:path*", {
                template:  '
'+
                                ''+
                           '
',
                controller: "FrameController"
            })
            .when('/404', {
                template: "
404

La página solicitada no existe.
"
            })
            .otherwise({redirectTo: '/404'});

});

app.controller('FrameController', function($scope, $mdSidenav, $routeParams) {
    $('.frame-ngPortal').load(function(){
        UIR.load.hide()
    })
    UIR.load.show("Cargando...")
    $('.frame-ngPortal').attr('src',"/"+$routeParams.path)
    $scope.size=$('body').height()-40
});

app.controller('EmbededController', function($scope, $mdSidenav) {

});

app.controller('MyController', function($scope, $mdSidenav) {
    $('.nav-sidebar a.nav-link').each(function(){
        if($(this).hasClass('ngPortal-embedded')){
            if($(this).attr("route"))
                $(this).attr("href",'#!/e'+$(this).attr("route"))
        }else{
            if($(this).attr("route"))
                $(this).attr("href",'#!/f'+$(this).attr("route"))
        }
    })

});

<commit_msg>Actualizando el registro de controladores ngPortal<commit_after>
var app = angular.module('ngPortalApp', ['ngRoute', 'ngMaterial']);
app.config(function($routeProvider, $locationProvider, $httpProvider,$controllerProvider) {
    app.controller = function (name, controller) {
        $controllerProvider.register(name, controller);
		return app;
    };

    $httpProvider.interceptors.push(function($q, $location) {
        return {
            'request': function(config) {

                config.headers['X-Requested-With'] = 'XMLHttpRequest'
                UIR.load.show('Cargando....')
                return config;
            },
            'responseError': function(rejection) {

                UIR.load.hide()
                if (!rejection.config.ignoreRequest && rejection.status == 404)
                    $location.path('/404')
                if (!rejection.config.ignoreRequest && rejection.status == 401) {
                    UIR.load.show('Autenticación detectada, redireccionando....')
                    window.location.href = '/'+Raptor.ngPortal.route+'/home'
                    return;
                }

                return $q.reject(rejection);
            },
            'response': function(response) {
                // same as above
                UIR.load.hide()
                return response;
            }
        };
    });

    $routeProvider
            .when('/',{redirectTo: '/e/'+Raptor.ngPortal.route+'/home/description'})
            .when("/e/:path*", {
                templateUrl: function(params) {
                    return "/" + params.path+ "?t=" + Date.now()
                },
                controller: "EmbededController"
            })
            .when("/f/:path*", {
                template:  '
'+
                                ''+
                           '
',
                controller: "FrameController"
            })
            .when('/404', {
                template: "
404

La página solicitada no existe.
"
            })
            .otherwise({redirectTo: '/404'});

});

app.controller('FrameController', function($scope, $mdSidenav, $routeParams) {
    $('.frame-ngPortal').load(function(){
        UIR.load.hide()
    })
    UIR.load.show("Cargando...")
    $('.frame-ngPortal').attr('src',"/"+$routeParams.path)
    $scope.size=$('body').height()-40
});

app.controller('EmbededController', function($scope, $mdSidenav) {

});

app.controller('MyController', function($scope, $mdSidenav) {
    $('.nav-sidebar a.nav-link').each(function(){
        if($(this).hasClass('ngPortal-embedded')){
            if($(this).attr("route"))
                $(this).attr("href",'#!/e'+$(this).attr("route"))
        }else{
            if($(this).attr("route"))
                $(this).attr("href",'#!/f'+$(this).attr("route"))
        }
    })

});

<|endoftext|>


<commit_before>var registerAddons = function(platform) {
    window['Icon.Entypo'] = require('react-native-vector-icons/Entypo');
    window['Icon.EvilIcons'] = require('react-native-vector-icons/EvilIcons');
    window['Icon.FontAwesome'] = require('react-native-vector-icons/FontAwesome');
    window['Icon.Foundation'] = require('react-native-vector-icons/Foundation');
    window['Icon.Ionicons'] = require('react-native-vector-icons/Ionicons');
    window['Icon.MaterialIcons'] = require('react-native-vector-icons/MaterialIcons');
    window['Icon.Octicons'] = require('react-native-vector-icons/Octicons');
    window['Icon.Zocial'] = require('react-native-vector-icons/Zocial');

    window['Animatable'] = require('react-native-animatable');

    if (platform !== 'web') {
      window['GL'] = require('gl-react-native');
    }
};

module.exports = {
  registerAddons: registerAddons
};

<commit_msg>remove gl-react-native from android, since somethings not working...<commit_after>var registerAddons = function(platform) {
    window['Icon.Entypo'] = require('react-native-vector-icons/Entypo');
    window['Icon.EvilIcons'] = require('react-native-vector-icons/EvilIcons');
    window['Icon.FontAwesome'] = require('react-native-vector-icons/FontAwesome');
    window['Icon.Foundation'] = require('react-native-vector-icons/Foundation');
    window['Icon.Ionicons'] = require('react-native-vector-icons/Ionicons');
    window['Icon.MaterialIcons'] = require('react-native-vector-icons/MaterialIcons');
    window['Icon.Octicons'] = require('react-native-vector-icons/Octicons');
    window['Icon.Zocial'] = require('react-native-vector-icons/Zocial');

    window['Animatable'] = require('react-native-animatable');
};

module.exports = {
  registerAddons: registerAddons
};

<|endoftext|>