<commit_before>'use strict';

/**
 * @module ChangeLog
 * @name ChangeLog
 * @description A record(log) of a changes on a service request(issue).
 *
 *              It may be status, priority, assignee change, private or public
 *              comments etc.
 *
 * @see {@link Party}
 * @see {@link ServiceRequest}
 * @see {@link Status}
 * @see {@link Priority}
 * @author lally elias <lallyelias87@mail.com>
 * @since 0.1.0
 * @version 0.1.0
 * @public
 */

//dependencies
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const ObjectId = Schema.Types.ObjectId;

//constants
// const VISIBILITY_PUBLIC = 'Public';
// const VISIBILITY_PRIVATE = 'Private';

//TODO hook on pre validation
//TODO hook on post save

/**
 * @name ChangeLogSchema
 * @type {Schema}
 * @since 0.1.0
 * @version 0.1.0
 * @private
 */
const ChangeLogSchema = new Schema({

  /**
   * @name status
   * @description A current assigned status
   * @type {Object}
   * @see {@link Status}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  status: {
    type: ObjectId,
    ref: 'Status',
    required: true,
    index: true,
    autoset: true,
    exists: true,
    autopopulate: true
  },

  /**
   * @name priority
   * @description A current assigned priority
   * @type {Object}
   * @see {@link Priority}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  priority: {
    type: ObjectId,
    ref: 'Priority',
    required: true,
    index: true,
    autoset: true,
    exists: true,
    autopopulate: true
  },

  /**
   * @name assignee
   * @description A current assigned party to work on service request(issue)
   * @type {Object}
   * @see {@link Priority}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  assignee: {
    type: ObjectId,
    ref: 'Party',
    required: true,
    index: true,
    autoset: true,
    exists: true,
    autopopulate: {
      select: 'name email phone'
    }
  },

  /**
   * @name changer
   * @description A party whose made changes
   * @type {Object}
   * @see {@link Party}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  changer: {
    type: ObjectId,
    ref: 'Party',
    required: true,
    index: true,
    autoset: true,
    exists: true,
    autopopulate: {
      select: 'name email phone'
    }
  },

  /**
   * @name remarks
   * @description A note provided by a change when changing a status
   * @type {Object}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  remarks: {
    type: String,
    index: true,
    trim: true,
    searchable: true
  },

  //TODO find best strategy for notifications
  /**
   * @name notify
   * @description Signal to send remarks to a service request(issue) reporter
   *              using sms, email etc.
   * @type {Object}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  notify: {
    type: Boolean,
    default: false
  },

  /**
   * @name isPublic
   * @description Signal if service request(issue) is public viewable.
   * @type {Object}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  isPublic: {
    type: Boolean,
    default: false
  }

}, { timestamps: true, emitIndexErrors: true });

/**
 * @name ChangeLogSchema
 * @description exports duration schema
 * @type {Schema}
 * @since  0.1.0
 * @version 0.1.0
 * @public
 */
module.exports = exports = ChangeLogSchema;
<commit_msg>improve changelog schema with additional fields<commit_after>'use strict';

/**
 * @module ChangeLog
 * @name ChangeLog
 * @description A record(log) of a changes on a service request(issue).
 *
 *              It may be status change, priority change, assignee change,
 *              private comment(internal note) or public comment etc.
 *
 * @see {@link ServiceRequest}
 * @see {@link Status}
 * @see {@link Party}
 * @see {@link Priority}
 * @author lally elias <lallyelias87@mail.com>
 * @since 0.1.0
 * @version 0.1.0
 * @public
 */

//global dependencies(or imports)
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const ObjectId = Schema.Types.ObjectId;

//local dependencies(or imports)

//constants
const VISIBILITY_PUBLIC = 'Public';
const VISIBILITY_PRIVATE = 'Private';
const VISIBILITIES = [VISIBILITY_PRIVATE, VISIBILITY_PUBLIC];

//TODO hook on service request pre validation
//TODO hook on service request post save
//TODO ensure notification is sent once there are changes
//TODO always sort them in order of update before send them
//TODO notify assignee once changed(previous and current)

/**
 * @name ChangeLogSchema
 * @type {Schema}
 * @since 0.1.0
 * @version 0.1.0
 * @private
 */
const ChangeLogSchema = new Schema({

  /**
   * @name status
   * @description A current assigned status of the service request.
   * @type {Status}
   * @see {@link Status}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  status: {
    type: ObjectId,
    ref: 'Status',
    index: true,
    autoset: true,
    exists: true,
    autopopulate: {
      select: 'name weight color'
    }
  },

  /**
   * @name priority
   * @description A current assigned priority of the service request
   * @type {Priority}
   * @see {@link Priority}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  priority: {
    type: ObjectId,
    ref: 'Priority',
    index: true,
    autoset: true,
    exists: true,
    autopopulate: {
      select: 'name weight color'
    }
  },

  /**
   * @name assignee
   * @description A current assigned party to work on service request(issue)
   * @type {Party}
   * @see {@link Priority}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  assignee: {
    type: ObjectId,
    ref: 'Party',
    index: true,
    autoset: true,
    exists: true,
    autopopulate: {
      select: 'name email phone'
    }
  },

  /**
   * @name changer
   * @description A party whose made changes to a servie request(issue)
   * @type {Object}
   * @see {@link Party}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  changer: {
    type: ObjectId,
    ref: 'Party',
    required: true,
    index: true,
    autoset: true,
    exists: true,
    autopopulate: {
      select: 'name email phone'
    }
  },

  /**
   * @name comment
   * @description A note provided by a change when changing a status.
   *
   *              It may be an internal note telling how far the service
   *              request(issue) has been worked on or a message to a reporter.
   *
   * @type {Object}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  comment: {
    type: String,
    index: true,
    trim: true,
    searchable: true
  },

  /**
   * @name shouldNotify
   * @description Signal to send notification to a service request(issue)
   *              reporter using sms, email etc. about work(progress) done
   *              so far to resolve the issue.
   *
   * @type {Object}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  shouldNotify: {
    type: Boolean,
    default: false
  },

  /**
   * @name wasNotificationSent
   * @description Tells if a notification contain a changes was
   *              sent to a service request(issue) reporter using
   *              sms, email etc. once a service request changed.
   *
   *              Note!: status changes trigger a notification to be sent
   *              always.
   *
   * @type {Object}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  wasNotificationSent: {
    type: Boolean,
    default: false
  },

  /**
   * @name visibility
   * @description Signal if this changelog is public or private viewable.
   *
   *              Note!: status changes are always public viewable by default.
   *
   * @type {Object}
   * @private
   * @since 0.1.0
   * @version 0.1.0
   */
  visibility: {
    type: String,
    index: true,
    enum: VISIBILITIES,
    default: VISIBILITY_PRIVATE
  }

}, { _id: false, timestamps: true, emitIndexErrors: true });

//---------------------------------------------------------
// ChangeLogSchema Hooks
//---------------------------------------------------------

/**
 * @name  preValidate
 * @description pre validation logics for changelog
 * @param  {Function} next a callback to be called after pre validation logics
 * @since  0.1.0
 * @version 0.1.0
 * @private
 */
ChangeLogSchema.pre('validate', function (next) {

  //always make status change to trigger notification
  //and public viewable
  if (this.status) {
    this.shouldNotify = true;
    this.visibility = VISIBILITY_PUBLIC;
  }

  //continue
  next();

});

//---------------------------------------------------------
// ChangeLogSchema Statics
//---------------------------------------------------------

//expose changelog visibility flags(constants)
ChangeLogSchema.VISIBILITY_PRIVATE =
  ChangeLogSchema.statics.VISIBILITY_PRIVATE = VISIBILITY_PRIVATE;

ChangeLogSchema.VISIBILITY_PUBLIC =
  ChangeLogSchema.statics.VISIBILITY_PUBLIC = VISIBILITY_PUBLIC;

//TODO post save send notification
//TODO for public comment notify reporter

/**
 * @name ChangeLogSchema
 * @description exports changelog schema
 * @type {Schema}
 * @since  0.1.0
 * @version 0.1.0
 * @public
 */
module.exports = exports = ChangeLogSchema;
<|endoftext|>


<commit_before>import { StackNavigator } from 'react-navigation';
import Icon from 'react-native-vector-icons/MaterialIcons';
import React from 'react';
import CardStackStyleInterpolator from 'react-navigation/src/views/CardStack/CardStackStyleInterpolator';

import { commonNavigationOptions, iconColor, iconSize } from './styles';
import FoiRequestsDetailsScreen from '../containers/foiRequests/FoiRequestsDetailsScreen';
import FoiRequestsIntroScreen from '../containers/foiRequests/FoiRequestsIntroScreen';
import FoiRequestsMasterScreen from '../containers/foiRequests/FoiRequestsMasterScreen';
import FoiRequestsPublicBodyScreen from '../containers/foiRequests/FoiRequestsPublicBodyScreen';
import I18n from '../i18n';
import PdfViewer from '../components/screens/PdfViewer';
import navigateOnce from '../utils/navigateOnce';

const FoiRequestsNavigator = StackNavigator(
  {
    FoiRequestsMaster: { screen: FoiRequestsMasterScreen },
    FoiRequestsDetails: { screen: FoiRequestsDetailsScreen },
    FoiRequestsPdfViewer: { screen: PdfViewer },
    FoiRequestsPublicBody: { screen: FoiRequestsPublicBodyScreen },
    FoiRequestsIntro: { screen: FoiRequestsIntroScreen },
  },
  {
    navigationOptions: {
      ...commonNavigationOptions,
      tabBarLabel: I18n.t('requests'),
      tabBarIcon: () => <Icon size={iconSize} color={iconColor} name="list" />,
    },
    // https://github.com/react-navigation/react-navigation/issues/3217
    transitionConfig: () => ({
      screenInterpolator: props => {
        // Transitioning to screen (navigate)
        if (props.scene.route.routeName === 'FoiRequestsIntro') {
          return CardStackStyleInterpolator.forFade(props);
        }

        const last = props.scenes[props.scenes.length - 1];

        // Transitioning from screen (goBack)
        if (last.route.routeName === 'FoiRequestsIntro') {
          return CardStackStyleInterpolator.forFade(props);
        }

        return CardStackStyleInterpolator.forHorizontal(props);
      },
    }),
  }
);

FoiRequestsNavigator.router.getStateForAction = navigateOnce(
  FoiRequestsNavigator.router.getStateForAction
);

export default FoiRequestsNavigator;
<commit_msg>don't use custom transitions for now<commit_after>import { StackNavigator } from 'react-navigation';
import Icon from 'react-native-vector-icons/MaterialIcons';
import React from 'react';
// import CardStackStyleInterpolator from 'react-navigation/src/views/CardStack/CardStackStyleInterpolator';

import { commonNavigationOptions, iconColor, iconSize } from './styles';
import FoiRequestsDetailsScreen from '../containers/foiRequests/FoiRequestsDetailsScreen';
import FoiRequestsIntroScreen from '../containers/foiRequests/FoiRequestsIntroScreen';
import FoiRequestsMasterScreen from '../containers/foiRequests/FoiRequestsMasterScreen';
import FoiRequestsPublicBodyScreen from '../containers/foiRequests/FoiRequestsPublicBodyScreen';
import I18n from '../i18n';
import PdfViewer from '../components/screens/PdfViewer';
import navigateOnce from '../utils/navigateOnce';

const FoiRequestsNavigator = StackNavigator(
  {
    FoiRequestsMaster: { screen: FoiRequestsMasterScreen },
    FoiRequestsDetails: { screen: FoiRequestsDetailsScreen },
    FoiRequestsPdfViewer: { screen: PdfViewer },
    FoiRequestsPublicBody: { screen: FoiRequestsPublicBodyScreen },
    FoiRequestsIntro: { screen: FoiRequestsIntroScreen },
  },
  {
    navigationOptions: {
      ...commonNavigationOptions,
      tabBarLabel: I18n.t('requests'),
      tabBarIcon: () => <Icon size={iconSize} color={iconColor} name="list" />,
    },
    // https://github.com/react-navigation/react-navigation/issues/3217
    // transitionConfig: () => ({
    //   screenInterpolator: props => {
    //     // Transitioning to screen (navigate)
    //     if (props.scene.route.routeName === 'FoiRequestsIntro') {
    //       return CardStackStyleInterpolator.forFade(props);
    //     }

    //     const last = props.scenes[props.scenes.length - 1];

    //     // Transitioning from screen (goBack)
    //     if (last.route.routeName === 'FoiRequestsIntro') {
    //       return CardStackStyleInterpolator.forFade(props);
    //     }

    //     return CardStackStyleInterpolator.forHorizontal(props);
    //   },
    // }),
  }
);

FoiRequestsNavigator.router.getStateForAction = navigateOnce(
  FoiRequestsNavigator.router.getStateForAction
);

export default FoiRequestsNavigator;
<|endoftext|>


<commit_before>const c = require('./../schemas')
const utils = require('core/utils');
const { LEFT_LANK_KEY, RIGHT_LANK_KEY, HERO_PET, BACKGROUND_OBJECT } = require('./../../../ozaria/engine/cinematic/constants')

const ThangTypeSchema = (title, description) => c.object({
  title,
  description,
  required: ['type']
}, {
  type: {
    oneOf: [
      c.shortString({
        title: 'Hero',
        description: 'Hero ThangType Id computed at runtime',
        enum: ['hero', 'avatar']
      }),
      c.object({
        title: 'Character Slug',
        description: 'The slug of the Character Thangtype.',
        required: ['slug']
      }, {
        slug: c.shortString({
          title: 'Slug',
          description: 'The thangType slug of the asset. Only required if this isn\'t the player hero.'
        })
      })
    ]
  },
  scaleX: c.float({
    title: 'scaleX',
    description: 'The scaling factor along x axis to apply to the ThangType'
  }),
  scaleY: c.float({
    title: 'scaleY',
    description: 'The scaling factor along y axis to apply to the ThangType'
  }),
  pos: c.point2d({
    title: 'Position',
    description: 'The position in meters to place the thangType.'
  })
})

const CharacterSchema = (title) => c.object({
  title: title,
  description: 'ThangType that will appear on either the left or right side of the screen.',
  required: ['thangType']
}, {
  thangType: ThangTypeSchema('Character', 'The thangType to display for this character'),
  enterOnStart: {
    type: 'boolean',
    title: 'Animate in?',
    description: 'If true the character will animate in. Otherwise the character will start simply there.'
  }
})

const ShotSetup = c.object({
  title: 'ShotSetup'
}, {
  shotContentType: c.shortString({ title: 'Content Type', description: 'Sets flag that all following shots are marked with, until this setting is used again. No runtime impact.', enum: ['story', 'education'], default: 'story' }),
  rightThangType: CharacterSchema('Right Character'),
  leftThangType: CharacterSchema('Left Character'),
  heroPetThangType: ThangTypeSchema('Hero Pet', 'The position property will be used to place the dog at an offset on the right lank.'),
  backgroundArt: ThangTypeSchema('Background Art', 'The rasterized image to place on the background'),
  camera: c.object({
    title: 'Camera placement',
    description: 'Where to place the camera at the beginning of the shot'
  }, {
    pos: c.point2d({
      title: 'Position',
      description: 'The position of the camera in meters.'
    }),
    zoom: {
      title: 'Zoom',
      description: 'The zoom level of the camera. A good default is \'2.01\'. There is a bug with the value 2. Recommended you change between 0 and 10.',
      type: 'number'
    }
  }),
  music: {
    oneOf: [
      c.object(
        { title: 'Music' },
        {
          files: c.sound(),
          loop: { type: 'boolean', default: false }
        }),

      // Legacy sound schema.  Present for backwards compatibility.
      c.sound()
    ]
  }
})

const DialogNode = c.object({
  title: 'Dialog Node',
  description: 'A node of a shot. Contains dialog instructions.',
  format: 'cinematic-dialog'
}, {
  speaker: c.shortString({ enum: ['left', 'right', 'center'], title: 'Speaker', description: 'Which character is speaking. Used to select speech bubble.' }),
  text: { type: 'string', title: 'Text', description: 'html text', maxLength: 500 },
  voiceOver: c.voiceOver,
  widthOverride: c.int({ title: 'Text Width(%)', description: 'The percent width of the text dialogue box based on the users screen size. Default is 31.' }),
  textAnimationLength: c.int({ title: 'Text Animation Length(ms)', description: 'The number of milliseconds it takes for the text to animate in.' }),
  speakingAnimationAction: c.shortString({ title: 'Speaking Animation', description: 'The animation to play on the lank while the text is being animated. If not set will default to "talkNeutral"' }),
  i18n: { type: 'object', format: 'i18n', props: ['text'], description: 'Help translate this cinematic dialogNode.' },
  waitUserInput: { type: 'boolean', title: 'User Input?', description: 'Whether or not user input is required to continue to the next dialog node or shot setup. Defaults to true.' },
  textLocation: c.object({ title: 'Text Location', description: 'An {x, y} coordinate point.', format: 'point2d', required: ['x', 'y'] }, {
    x: { title: 'x', description: 'The x coordinate.', type: 'number', 'default': 0 },
    y: { title: 'y', description: 'The y coordinate.', type: 'number', 'default': 0 } }),
  programmingLanguageFilter: c.shortString({ enum: ['python', 'javascript'], title: 'Programming Language Filter', description: 'If set, this node is only shown if the user is using the programming language selected.' }),
  visualChalkBoardData: c.object({
    title: 'Visual Chalkboard Data'
  }, {
    chalkboardContent: {
      oneOf: [
        { title: 'Markdown Content', type: 'string', maxLength: 4000, description: 'Content to place in the chalkboard', format: 'markdown' },
        {
          type: 'object',
          title: 'Rich Text Content',
          format: 'rich-text'
        }
      ]
    },
    width: { title: 'width (%)', description: 'The chalkboard width.', type: 'number', 'default': 45 },
    height: { title: 'height (%)', type: 'number', 'default': 75 },
    xOffset: { title: 'X offset (%)', description: 'An offset from the center along x', type: 'number', 'default': 46 },
    yOffset: { title: 'Y offset (%)', description: 'An offset from the center along y', type: 'number', 'default': 26 }
  }),
  mutators: c.object({
    title: 'Mutators',
    description: 'Properties that change cinematic going forward'
  }, {
    changeDefaultIdles: c.array({
      title: 'List of idles to change',
      description: 'Changes the action that is run for the idle state for provided character'
    },
    c.object({
      title: 'Change Idle Action',
      description: 'Setting this will update the default idle action for the rest of the cinematic. The default value is \'idle\'.'
    }, {
      character: c.shortString({ title: 'Character', description: 'Which character has default idle action updated', ...(utils.isCodeCombat ? {} : { enum: [LEFT_LANK_KEY, RIGHT_LANK_KEY, BACKGROUND_OBJECT] }) }),
      newIdleAction: c.shortString({ title: 'New Idle Action' })
    })
    ),
    showVisualChalkboard: {
      title: 'Show Visual Chalkboard',
      type: 'boolean',
      description: 'Show the visual chalkboard',
      default: true
    },
    fadeToBlack: c.object({
      title: 'Fade To Black'
    }, {
      duration: c.int({ title: 'Duration(ms)', default: 400 })
    }),
    fadeFromBlack: c.object({
      title: 'Fade From Black'
    }, {
      duration: c.int({ title: 'Duration(ms)', default: 400 })
    })
  }),
  triggers: c.object({
    title: 'Triggers',
    description: 'Events that can occur during the dialogue.'
  }, {
    backgroundObject: c.object({
      title: 'Background Object',
      description: 'Add a background object after given duration',
      required: ['thangType', 'triggerStart']
    }, {
      thangType: ThangTypeSchema('Background Object', 'The image to place'),
      triggerStart: c.int({ title: 'Trigger Start(ms)', description: 'The number of milliseconds until background image art appears' })
    }),
    clearBackgroundObject: c.object({
      title: 'Clear Background Object',
      description: 'Clears the background objects from the screen after a given duration'
    }, {
      triggerStart: c.int({ title: 'Trigger Start(ms)', description: 'The number of milliseconds until background object is cleared' })
    }),
    playThangAnimations: c.array({
      title: 'Thang Animation triggers'
    }, c.object({
      title: 'Trigger Thang Action',
      description: 'Triggers an animation to play after a duration for a given time.',
      required: ['duration', 'animation', 'lankTarget']
    }, {
      delay: c.int({ title: 'Delay(ms)' }),
      duration: c.int({ title: 'Duration(ms)' }),
      animation: c.shortString({ title: 'Animation', description: 'Animation to trigger on the ThangType' }),
      lankTarget: c.shortString({ title: 'Thang', description: 'Thang on stage to play animation on', ...(utils.isCodeCombat ? {} : { enum: [LEFT_LANK_KEY, RIGHT_LANK_KEY, HERO_PET, BACKGROUND_OBJECT] }) })
    })),
    soundFxTriggers: c.array({
      title: 'SoundFX triggers',
      description: 'A list of sound effects that we can play. Unlike music they will overlap and wont prevent other sounds playing.'
    },
    c.object({
      title: 'Sound Effect',
      description: 'A sound effect that plays after a delay.',
      required: ['sound']
    }, {
      sound: c.sound(),
      triggerStart: c.int({ title: 'Trigger Start(ms)', description: 'The number of milliseconds until the sound effect is played' })
    }))
  }),
  dialogClear: {
    type: 'boolean',
    title: 'Clear dialog on screen',
    description: 'Whether we clear any existing dialog nodes.'
  },
  exitCharacter: c.shortString({ title: 'Exit Character', description: 'whether character exits at dialog node completion', enum: ['left', 'right', 'both'] })
})

const Shot = c.object({
  title: 'Shot',
  description: 'A single shot, setting up camera and running dialog nodes'
}, {
  shotSetup: ShotSetup,
  dialogNodes: c.array({
    title: 'Dialog Nodes',
    description: 'List of all possible nodes in the shot.'
  }, DialogNode)
})

const CinematicSchema = c.object({
  description: 'A cinematic composed of shots.',
  title: 'Cinematic'
}, {
  i18n: { type: 'object', format: 'i18n', props: ['name', 'displayName'], description: 'Help translate this level' },
  shots: c.array({
    title: 'Shots',
    description: 'Ordered list of shots that make up a cinematic'
  }, Shot),
  displayName: c.shortString({ title: 'Display Name' }),
  description: { type: 'string', title: 'Description', description: 'Relevant for teacher dashboard' },
  showInstructionalTooltip: { title: 'Show Instructional Tooltip', description: 'Trigger instructions on how to navigate cinematics for users', type: 'boolean', default: true }
})

c.extendBasicProperties(CinematicSchema, 'cinematic')
c.extendNamedProperties(CinematicSchema)
c.extendTranslationCoverageProperties(CinematicSchema)
c.extendPatchableProperties(CinematicSchema)

module.exports = CinematicSchema
<commit_msg>Fix server-client require issue<commit_after>const c = require('./../schemas')
const { LEFT_LANK_KEY, RIGHT_LANK_KEY, HERO_PET, BACKGROUND_OBJECT } = require('./../../../ozaria/engine/cinematic/constants')

const ThangTypeSchema = (title, description) => c.object({
  title,
  description,
  required: ['type']
}, {
  type: {
    oneOf: [
      c.shortString({
        title: 'Hero',
        description: 'Hero ThangType Id computed at runtime',
        enum: ['hero', 'avatar']
      }),
      c.object({
        title: 'Character Slug',
        description: 'The slug of the Character Thangtype.',
        required: ['slug']
      }, {
        slug: c.shortString({
          title: 'Slug',
          description: 'The thangType slug of the asset. Only required if this isn\'t the player hero.'
        })
      })
    ]
  },
  scaleX: c.float({
    title: 'scaleX',
    description: 'The scaling factor along x axis to apply to the ThangType'
  }),
  scaleY: c.float({
    title: 'scaleY',
    description: 'The scaling factor along y axis to apply to the ThangType'
  }),
  pos: c.point2d({
    title: 'Position',
    description: 'The position in meters to place the thangType.'
  })
})

const CharacterSchema = (title) => c.object({
  title: title,
  description: 'ThangType that will appear on either the left or right side of the screen.',
  required: ['thangType']
}, {
  thangType: ThangTypeSchema('Character', 'The thangType to display for this character'),
  enterOnStart: {
    type: 'boolean',
    title: 'Animate in?',
    description: 'If true the character will animate in. Otherwise the character will start simply there.'
  }
})

const ShotSetup = c.object({
  title: 'ShotSetup'
}, {
  shotContentType: c.shortString({ title: 'Content Type', description: 'Sets flag that all following shots are marked with, until this setting is used again. No runtime impact.', enum: ['story', 'education'], default: 'story' }),
  rightThangType: CharacterSchema('Right Character'),
  leftThangType: CharacterSchema('Left Character'),
  heroPetThangType: ThangTypeSchema('Hero Pet', 'The position property will be used to place the dog at an offset on the right lank.'),
  backgroundArt: ThangTypeSchema('Background Art', 'The rasterized image to place on the background'),
  camera: c.object({
    title: 'Camera placement',
    description: 'Where to place the camera at the beginning of the shot'
  }, {
    pos: c.point2d({
      title: 'Position',
      description: 'The position of the camera in meters.'
    }),
    zoom: {
      title: 'Zoom',
      description: 'The zoom level of the camera. A good default is \'2.01\'. There is a bug with the value 2. Recommended you change between 0 and 10.',
      type: 'number'
    }
  }),
  music: {
    oneOf: [
      c.object(
        { title: 'Music' },
        {
          files: c.sound(),
          loop: { type: 'boolean', default: false }
        }),

      // Legacy sound schema.  Present for backwards compatibility.
      c.sound()
    ]
  }
})

const DialogNode = c.object({
  title: 'Dialog Node',
  description: 'A node of a shot. Contains dialog instructions.',
  format: 'cinematic-dialog'
}, {
  speaker: c.shortString({ enum: ['left', 'right', 'center'], title: 'Speaker', description: 'Which character is speaking. Used to select speech bubble.' }),
  text: { type: 'string', title: 'Text', description: 'html text', maxLength: 500 },
  voiceOver: c.voiceOver,
  widthOverride: c.int({ title: 'Text Width(%)', description: 'The percent width of the text dialogue box based on the users screen size. Default is 31.' }),
  textAnimationLength: c.int({ title: 'Text Animation Length(ms)', description: 'The number of milliseconds it takes for the text to animate in.' }),
  speakingAnimationAction: c.shortString({ title: 'Speaking Animation', description: 'The animation to play on the lank while the text is being animated. If not set will default to "talkNeutral"' }),
  i18n: { type: 'object', format: 'i18n', props: ['text'], description: 'Help translate this cinematic dialogNode.' },
  waitUserInput: { type: 'boolean', title: 'User Input?', description: 'Whether or not user input is required to continue to the next dialog node or shot setup. Defaults to true.' },
  textLocation: c.object({ title: 'Text Location', description: 'An {x, y} coordinate point.', format: 'point2d', required: ['x', 'y'] }, {
    x: { title: 'x', description: 'The x coordinate.', type: 'number', 'default': 0 },
    y: { title: 'y', description: 'The y coordinate.', type: 'number', 'default': 0 } }),
  programmingLanguageFilter: c.shortString({ enum: ['python', 'javascript'], title: 'Programming Language Filter', description: 'If set, this node is only shown if the user is using the programming language selected.' }),
  visualChalkBoardData: c.object({
    title: 'Visual Chalkboard Data'
  }, {
    chalkboardContent: {
      oneOf: [
        { title: 'Markdown Content', type: 'string', maxLength: 4000, description: 'Content to place in the chalkboard', format: 'markdown' },
        {
          type: 'object',
          title: 'Rich Text Content',
          format: 'rich-text'
        }
      ]
    },
    width: { title: 'width (%)', description: 'The chalkboard width.', type: 'number', 'default': 45 },
    height: { title: 'height (%)', type: 'number', 'default': 75 },
    xOffset: { title: 'X offset (%)', description: 'An offset from the center along x', type: 'number', 'default': 46 },
    yOffset: { title: 'Y offset (%)', description: 'An offset from the center along y', type: 'number', 'default': 26 }
  }),
  mutators: c.object({
    title: 'Mutators',
    description: 'Properties that change cinematic going forward'
  }, {
    changeDefaultIdles: c.array({
      title: 'List of idles to change',
      description: 'Changes the action that is run for the idle state for provided character'
    },
    c.object({
      title: 'Change Idle Action',
      description: 'Setting this will update the default idle action for the rest of the cinematic. The default value is \'idle\'.'
    }, {
      character: c.shortString({ title: 'Character', description: 'Which character has default idle action updated', enum: [LEFT_LANK_KEY, RIGHT_LANK_KEY, BACKGROUND_OBJECT] }),
      newIdleAction: c.shortString({ title: 'New Idle Action' })
    })
    ),
    showVisualChalkboard: {
      title: 'Show Visual Chalkboard',
      type: 'boolean',
      description: 'Show the visual chalkboard',
      default: true
    },
    fadeToBlack: c.object({
      title: 'Fade To Black'
    }, {
      duration: c.int({ title: 'Duration(ms)', default: 400 })
    }),
    fadeFromBlack: c.object({
      title: 'Fade From Black'
    }, {
      duration: c.int({ title: 'Duration(ms)', default: 400 })
    })
  }),
  triggers: c.object({
    title: 'Triggers',
    description: 'Events that can occur during the dialogue.'
  }, {
    backgroundObject: c.object({
      title: 'Background Object',
      description: 'Add a background object after given duration',
      required: ['thangType', 'triggerStart']
    }, {
      thangType: ThangTypeSchema('Background Object', 'The image to place'),
      triggerStart: c.int({ title: 'Trigger Start(ms)', description: 'The number of milliseconds until background image art appears' })
    }),
    clearBackgroundObject: c.object({
      title: 'Clear Background Object',
      description: 'Clears the background objects from the screen after a given duration'
    }, {
      triggerStart: c.int({ title: 'Trigger Start(ms)', description: 'The number of milliseconds until background object is cleared' })
    }),
    playThangAnimations: c.array({
      title: 'Thang Animation triggers'
    }, c.object({
      title: 'Trigger Thang Action',
      description: 'Triggers an animation to play after a duration for a given time.',
      required: ['duration', 'animation', 'lankTarget']
    }, {
      delay: c.int({ title: 'Delay(ms)' }),
      duration: c.int({ title: 'Duration(ms)' }),
      animation: c.shortString({ title: 'Animation', description: 'Animation to trigger on the ThangType' }),
      lankTarget: c.shortString({ title: 'Thang', description: 'Thang on stage to play animation on', enum: [LEFT_LANK_KEY, RIGHT_LANK_KEY, HERO_PET, BACKGROUND_OBJECT] })
    })),
    soundFxTriggers: c.array({
      title: 'SoundFX triggers',
      description: 'A list of sound effects that we can play. Unlike music they will overlap and wont prevent other sounds playing.'
    },
    c.object({
      title: 'Sound Effect',
      description: 'A sound effect that plays after a delay.',
      required: ['sound']
    }, {
      sound: c.sound(),
      triggerStart: c.int({ title: 'Trigger Start(ms)', description: 'The number of milliseconds until the sound effect is played' })
    }))
  }),
  dialogClear: {
    type: 'boolean',
    title: 'Clear dialog on screen',
    description: 'Whether we clear any existing dialog nodes.'
  },
  exitCharacter: c.shortString({ title: 'Exit Character', description: 'whether character exits at dialog node completion', enum: ['left', 'right', 'both'] })
})

const Shot = c.object({
  title: 'Shot',
  description: 'A single shot, setting up camera and running dialog nodes'
}, {
  shotSetup: ShotSetup,
  dialogNodes: c.array({
    title: 'Dialog Nodes',
    description: 'List of all possible nodes in the shot.'
  }, DialogNode)
})

const CinematicSchema = c.object({
  description: 'A cinematic composed of shots.',
  title: 'Cinematic'
}, {
  i18n: { type: 'object', format: 'i18n', props: ['name', 'displayName'], description: 'Help translate this level' },
  shots: c.array({
    title: 'Shots',
    description: 'Ordered list of shots that make up a cinematic'
  }, Shot),
  displayName: c.shortString({ title: 'Display Name' }),
  description: { type: 'string', title: 'Description', description: 'Relevant for teacher dashboard' },
  showInstructionalTooltip: { title: 'Show Instructional Tooltip', description: 'Trigger instructions on how to navigate cinematics for users', type: 'boolean', default: true }
})

c.extendBasicProperties(CinematicSchema, 'cinematic')
c.extendNamedProperties(CinematicSchema)
c.extendTranslationCoverageProperties(CinematicSchema)
c.extendPatchableProperties(CinematicSchema)

module.exports = CinematicSchema
<|endoftext|>


<commit_before>/**
 * @preserve base64.js v0.2.0 (c) 2012 knowledgecode | MIT licensed
 */
/*global atob, btoa, escape, unescape */
/*jslint bitwise: true, browser: true, plusplus: true */
(function () {
    'use strict';

    var id = 'base64',
        m = {},
        b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';

    /**
     * @name encode
     * @function
     * @param {string} str
     * @return {string} encoded string
     */
    m.encode = (function () {
        if (btoa) {
            return function (str) {
                return btoa(unescape(encodeURIComponent(str)));
            };
        }
        return function (str) {
            var i, j, len, a1, a2, a3, b1, b2, b3, b4, value = [];

            str = unescape(encodeURIComponent(str));
            for (i = 0, j = 0, len = str.length; i < len; i += 3) {
                a1 = str.charCodeAt(i) || 0;
                a2 = str.charCodeAt(i + 1) || 0;
                a3 = str.charCodeAt(i + 2) || 0;

                b1 = (a1 >> 2) & 0x3F;
                b2 = ((a1 & 0x03) << 4) | ((a2 >> 4) & 0x0F);
                b3 = ((a2 & 0x0F) << 2) | ((a3 >> 6) & 0x03);
                b4 = a3 & 0x3F;

                if (!a3) {
                    b4 = 64;
                    if (!a2) {
                        b3 = 64;
                    }
                }
                value[j] = b64.charAt(b1);
                value[j + 1] = b64.charAt(b2);
                value[j + 2] = b64.charAt(b3);
                value[j + 3] = b64.charAt(b4);
                j += 4;
            }
            return value.join('');
        };
    }());

    /**
     * @name decode
     * @function
     * @param {string} str
     * @return {string} decoded string
     */
    m.decode = (function () {
        if (atob) {
            return function (str) {
                return decodeURIComponent(escape(atob(str)));
            };
        }
        return function (str) {
            var i, j, len, b1, b2, b3, b4, a1, a2, a3, value = [];

            str = str.replace(/\=+$/, '');
            for (i = 0, j = -1, len = str.length; i < len; i += 4) {
                b1 = b64.indexOf(str.charAt(i));
                b2 = b64.indexOf(str.charAt(i + 1));
                b3 = b64.indexOf(str.charAt(i + 2));
                b4 = b64.indexOf(str.charAt(i + 3));

                a1 = ((b1 & 0x3F) << 2) | ((b2 >> 4) & 0x03);
                a2 = ((b2 & 0x0F) << 4) | ((b3 >> 2) & 0x0F);
                a3 = ((b3 & 0x03) << 6) | (b4 & 0x3F);

                value[j++] = String.fromCharCode(a1);
                if (a2) {
                    value[j++] = String.fromCharCode(a2);
                    if (a3) {
                        value[j++] = String.fromCharCode(a3);
                    }
                }
            }
            return decodeURIComponent(escape(value.join('')));
        };
    }());

    /**
     * @name encodeSafe
     * @function
     * @param {string} str
     * @return {string} encoded string (web safe)
     */
    m.encodeSafe = function (str) {
        return m.encode(str).
            replace(/\+/g, '-').replace(/\//g, '_').replace(/\=/g, '.');
    };

    /**
     * @name decodeSafe
     * @function
     * @param {string} str
     * @return {string} decoded string (web safe)
     */
    m.decodeSafe = function (str) {
        return m.decode(
            str.replace(/-/g, '+').replace(/_/g, '/').replace(/\./g, '=')
        );
    };

    // Exposing module
    /*global lego, module */
    if (typeof lego === 'object' && lego.define) {
        // lego.js
        /*jslint unparam: true */
        lego.define(id, [], function (require, exports, module) {
            module.exports = m;
        });
    } else if (typeof module === 'object' && module.exports) {
        // CommonJS
        module.exports = m;
    } else {
        // Browser
        window[id] = m;
    }

}());
<commit_msg>fix a bug<commit_after>/**
 * @preserve base64.js v0.2.1 (c) 2012 knowledgecode | MIT licensed
 */
/*global escape, unescape */
/*jslint bitwise: true, browser: true, plusplus: true */
(function () {
    'use strict';

    var id = 'base64',
        m = {},
        b64e = [
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
            'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '='
        ],
        b64d = {
            'A': 0,
            'B': 1,
            'C': 2,
            'D': 3,
            'E': 4,
            'F': 5,
            'G': 6,
            'H': 7,
            'I': 8,
            'J': 9,
            'K': 10,
            'L': 11,
            'M': 12,
            'N': 13,
            'O': 14,
            'P': 15,
            'Q': 16,
            'R': 17,
            'S': 18,
            'T': 19,
            'U': 20,
            'V': 21,
            'W': 22,
            'X': 23,
            'Y': 24,
            'Z': 25,
            'a': 26,
            'b': 27,
            'c': 28,
            'd': 29,
            'e': 30,
            'f': 31,
            'g': 32,
            'h': 33,
            'i': 34,
            'j': 35,
            'k': 36,
            'l': 37,
            'm': 38,
            'n': 39,
            'o': 40,
            'p': 41,
            'q': 42,
            'r': 43,
            's': 44,
            't': 45,
            'u': 46,
            'v': 47,
            'w': 48,
            'x': 49,
            'y': 50,
            'z': 51,
            '0': 52,
            '1': 53,
            '2': 54,
            '3': 55,
            '4': 56,
            '5': 57,
            '6': 58,
            '7': 59,
            '8': 60,
            '9': 61,
            '+': 62,
            '/': 63
        };

    /**
     * @name encode
     * @function
     * @param {string} str
     * @return {string} encoded string
     */
    m.encode = (function () {
        if (window.btoa) {
            return function (str) {
                return window.btoa(unescape(encodeURIComponent(str)));
            };
        }
        return function (str) {
            var i = 0, j = 0, len, a1, a2, a3, b1, b2, b3, b4, value = [];

            str = unescape(encodeURIComponent(str));
            len = str.length;
            while (i < len) {
                a1 = str.charCodeAt(i++) || 0;
                a2 = str.charCodeAt(i++) || 0;
                a3 = str.charCodeAt(i++) || 0;

                b1 = (a1 >> 2) & 0x3F;
                b2 = ((a1 & 0x03) << 4) | ((a2 >> 4) & 0x0F);
                b3 = ((a2 & 0x0F) << 2) | ((a3 >> 6) & 0x03);
                b4 = a3 & 0x3F;

                if (!a3) {
                    b4 = 64;
                    if (!a2) {
                        b3 = 64;
                    }
                }
                value[j++] = b64e[b1];
                value[j++] = b64e[b2];
                value[j++] = b64e[b3];
                value[j++] = b64e[b4];
            }
            return value.join('');
        };
    }());

    /**
     * @name decode
     * @function
     * @param {string} str
     * @return {string} decoded string
     */
    m.decode = (function () {
        if (window.atob) {
            return function (str) {
                return decodeURIComponent(escape(window.atob(str)));
            };
        }
        return function (str) {
            var i = 0, j = 0, len, b1, b2, b3, b4, a1, a2, a3, value = [];

            str = str.replace(/\=+$/, '').split('');
            len = str.length;
            while (i < len) {
                b1 = b64d[str[i++]] || '';
                b2 = b64d[str[i++]] || '';
                b3 = b64d[str[i++]] || '';
                b4 = b64d[str[i++]] || '';

                a1 = ((b1 & 0x3F) << 2) | ((b2 >> 4) & 0x03);
                a2 = ((b2 & 0x0F) << 4) | ((b3 >> 2) & 0x0F);
                a3 = ((b3 & 0x03) << 6) | (b4 & 0x3F);

                value[j++] = String.fromCharCode(a1);
                if (a2) {
                    value[j++] = String.fromCharCode(a2);
                    if (a3) {
                        value[j++] = String.fromCharCode(a3);
                    }
                }
            }
            return decodeURIComponent(escape(value.join('')));
        };
    }());

    /**
     * @name encodeSafe
     * @function
     * @param {string} str
     * @return {string} encoded string (web safe)
     */
    m.encodeSafe = function (str) {
        return m.encode(str).
            replace(/\+/g, '-').replace(/\//g, '_').replace(/\=/g, '.');
    };

    /**
     * @name decodeSafe
     * @function
     * @param {string} str
     * @return {string} decoded string (web safe)
     */
    m.decodeSafe = function (str) {
        return m.decode(
            str.replace(/-/g, '+').replace(/_/g, '/').replace(/\./g, '=')
        );
    };

    // Exposing module
    /*global lego, module */
    if (typeof lego === 'object' && lego.define) {
        // lego.js
        /*jslint unparam: true */
        lego.define(id, [], function (require, exports, module) {
            module.exports = m;
        });
    } else if (typeof module === 'object' && module.exports) {
        // CommonJS
        module.exports = m;
    } else {
        // Browser
        window[id] = m;
    }

}());
<|endoftext|>


<commit_before>// Generated by CoffeeScript 1.3.3

/* ============================================================
# bootstrap-tour.js v0.1
# http://pushly.github.com/bootstrap-tour/
# ==============================================================
# Copyright 2012 Push.ly
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
*/

(function() {

  (function($, window) {
    var Tour, document;
    document = window.document;
    Tour = (function() {

      function Tour(options) {
        var _this = this;
        this._options = $.extend({
          name: 'tour',
          end: 'End tour',
          next: 'Next »',
          previous: '« Prev',
          afterSetState: function(key, value) {},
          afterGetState: function(key, value) {},
          onShow: function(tour) {},
          onHide: function(tour) {}
        }, options);
        this._steps = [];
        this.setCurrentStep();
        $(document).on("click", ".popover .next", function(e) {
          e.preventDefault();
          return _this.next();
        });
        $(document).on("click", ".popover .prev", function(e) {
          e.preventDefault();
          return _this.prev();
        });
        $(document).on("click", ".popover .end", function(e) {
          e.preventDefault();
          return _this.end();
        });
      }

      Tour.prototype.setState = function(key, value) {
        $.cookie("" + this._options.name + "_" + key, value, {
          expires: 36500,
          path: '/'
        });
        return this._options.afterSetState(key, value);
      };

      Tour.prototype.getState = function(key) {
        var value;
        value = $.cookie("" + this._options.name + "_" + key);
        this._options.afterGetState(key, value);
        return value;
      };

      Tour.prototype.addStep = function(step) {
        return this._steps.push(step);
      };

      Tour.prototype.getStep = function(i) {
        if (this._steps[i] != null) {
          return $.extend({
            path: "",
            placement: "right",
            title: "",
            content: "",
            next: i === this._steps.length - 1 ? -1 : i + 1,
            prev: i - 1,
            animation: true,
            onShow: this._options.onShow,
            onHide: this._options.onHide
          }, this._steps[i]);
        }
      };

      Tour.prototype.start = function(force) {
        if (force == null) {
          force = false;
        }
        if (force || !this.ended()) {
          return this.showStep(this._current);
        }
      };

      Tour.prototype.next = function() {
        this.hideStep(this._current);
        return this.showNextStep();
      };

      Tour.prototype.prev = function() {
        this.hideStep(this._current);
        return this.showPrevStep();
      };

      Tour.prototype.end = function() {
        this.hideStep(this._current);
        return this.setState("end", "yes");
      };

      Tour.prototype.ended = function() {
        return !!this.getState("end");
      };

      Tour.prototype.restart = function() {
        this.setState("current_step", null);
        this.setState("end", null);
        this.setCurrentStep(0);
        return this.start();
      };

      Tour.prototype.hideStep = function(i) {
        var step;
        step = this.getStep(i);
        if (step.onHide != null) {
          step.onHide(this);
        }
        return $(step.element).popover("hide");
      };

      Tour.prototype.showStep = function(i) {
        var step;
        step = this.getStep(i);
        if (!step) {
          return;
        }
        this.setCurrentStep(i);
        if (step.path !== "" && document.location.pathname !== step.path && document.location.pathname.replace(/^.*[\\\/]/, '') !== step.path) {
          document.location.href = step.path;
          return;
        }
        if (step.onShow != null) {
          step.onShow(this);
        }
        if (!((step.element != null) && $(step.element).length !== 0 && $(step.element).is(":visible"))) {
          this.showNextStep();
          return;
        }
        return this._showPopover(step, i);
      };

      Tour.prototype.setCurrentStep = function(value) {
        if (value != null) {
          this._current = value;
          return this.setState("current_step", value);
        } else {
          this._current = this.getState("current_step");
          if (this._current === null || this._current === "null") {
            return this._current = 0;
          } else {
            return this._current = parseInt(this._current);
          }
        }
      };

      Tour.prototype.showNextStep = function() {
        var step;
        step = this.getStep(this._current);
        return this.showStep(step.next);
      };

      Tour.prototype.showPrevStep = function() {
        var step;
        step = this.getStep(this._current);
        return this.showStep(step.prev);
      };

      Tour.prototype._showPopover = function(step, i) {
        var content, nav, tip, position, this_;
        this_ = this;
        //.popover-fixed {
        // position: fixed;
        //}
        position = (step.position && step.position == 'fixed') ? ' popover-fixed' : '';
        content = "" + step.content + "
";
        nav = [];
        if (step.reflex)
        {
          $(step.element).on('click', function(e) {
            this_.hideStep(this_._current);
            if (step.next)
              this_._current = step.next;
            this_.showNextStep();
          });
        }
        if (step.prev >= 0) {
          nav.push("" + step.options.previous + "");
        }
        if (step.next >= 0) {
          nav.push("" + step.options.next + "");
        }
        content += nav.join(" | ");
        content += "" + step.options.end + "";
        $(step.element).popover({
          placement: step.placement,
          trigger: "manual",
          title: step.title,
          content: Kontest.backend.jed.translate(content).onDomain(Kontest.lang).fetch(),
          animation: step.animation,
          template: '

'
        }).popover("show");
        tip = $(step.element).data("popover").tip();
        this._reposition(tip);
        if (!step.position)
          return this._scrollIntoView(tip);
        tip.css('top', $(step.element).get(0).offsetHeight + 'px');
        return ;
      };

      Tour.prototype._reposition = function(tip) {
        var offsetBottom, offsetRight, tipOffset;
        tipOffset = tip.offset();
        offsetBottom = $(document).outerHeight() - tipOffset.top - $(tip).outerHeight();
        if (offsetBottom < 0) {
          tipOffset.top = tipOffset.top + offsetBottom;
        }
        offsetRight = $(document).outerWidth() - tipOffset.left - $(tip).outerWidth();
        if (offsetRight < 0) {
          tipOffset.left = tipOffset.left + offsetRight;
        }
        if (tipOffset.top < 0) {
          tipOffset.top = 0;
        }
        if (tipOffset.left < 0) {
          tipOffset.left = 0;
        }
        return tip.offset(tipOffset);
      };

      Tour.prototype._scrollIntoView = function(tip) {
        var tipRect;
        tipRect = tip.get(0).getBoundingClientRect();
        if (!(tipRect.top > 0 && tipRect.bottom < $(window).height() && tipRect.left > 0 && tipRect.right < $(window).width())) {
          return tip.get(0).scrollIntoView(true);
        }
      };

      return Tour;

    })();
    return window.Tour = Tour;
  })(jQuery, window);

}).call(this);
<commit_msg>just commit*<commit_after>// Generated by CoffeeScript 1.3.3

/* ============================================================
# bootstrap-tour.js v0.1
# http://pushly.github.com/bootstrap-tour/
# ==============================================================
# Copyright 2012 Push.ly
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
*/

(function() {

  (function($, window) {
    var Tour, document;
    document = window.document;
    Tour = (function() {

      function Tour(options) {
        var _this = this;
        this._options = $.extend({
          name: 'tour',
          end: 'End tour',
          next: 'Next »',
          previous: '« Prev',
          afterSetState: function(key, value) {},
          afterGetState: function(key, value) {},
          onShow: function(tour) {},
          onHide: function(tour) {}
        }, options);
        this._steps = [];
        this.setCurrentStep();
        $(document).on("click", ".popover .next", function(e) {
          e.preventDefault();
          return _this.next();
        });
        $(document).on("click", ".popover .prev", function(e) {
          e.preventDefault();
          return _this.prev();
        });
        $(document).on("click", ".popover .end", function(e) {
          e.preventDefault();
          return _this.end();
        });
      }

      Tour.prototype.setState = function(key, value) {
        $.cookie("" + this._options.name + "_" + key, value, {
          expires: 36500,
          path: '/'
        });
        return this._options.afterSetState(key, value);
      };

      Tour.prototype.getState = function(key) {
        var value;
        value = $.cookie("" + this._options.name + "_" + key);
        this._options.afterGetState(key, value);
        return value;
      };

      Tour.prototype.addStep = function(step) {
        return this._steps.push(step);
      };

      Tour.prototype.getStep = function(i) {
        if (this._steps[i] != null) {
          return $.extend({
            path: "",
            placement: "right",
            title: "",
            content: "",
            next: i === this._steps.length - 1 ? -1 : i + 1,
            prev: i - 1,
            animation: true,
            onShow: this._options.onShow,
            onHide: this._options.onHide
          }, this._steps[i]);
        }
      };

      Tour.prototype.start = function(force) {
        if (force == null) {
          force = false;
        }
        if (force || !this.ended()) {
          return this.showStep(this._current);
        }
      };

      Tour.prototype.next = function() {
        this.hideStep(this._current);
        return this.showNextStep();
      };

      Tour.prototype.prev = function() {
        this.hideStep(this._current);
        return this.showPrevStep();
      };

      Tour.prototype.end = function() {
        this.hideStep(this._current);
        return this.setState("end", "yes");
      };

      Tour.prototype.ended = function() {
        return !!this.getState("end");
      };

      Tour.prototype.restart = function() {
        this.setState("current_step", null);
        this.setState("end", null);
        this.setCurrentStep(0);
        return this.start();
      };

      Tour.prototype.hideStep = function(i) {
        var step;
        step = this.getStep(i);
        if (step.onHide != null) {
          step.onHide(this);
        }
        return $(step.element).popover("hide");
      };

      Tour.prototype.showStep = function(i) {
        var step;
        step = this.getStep(i);
        if (!step) {
          return;
        }
        this.setCurrentStep(i);
        if (step.path !== "" && document.location.pathname !== step.path && document.location.pathname.replace(/^.*[\\\/]/, '') !== step.path) {
          document.location.href = step.path;
          return;
        }
        if (step.onShow != null) {
          step.onShow(this);
        }
        if (!((step.element != null) && $(step.element).length !== 0 && $(step.element).is(":visible"))) {
          this.showNextStep();
          return;
        }
        return this._showPopover(step, i);
      };

      Tour.prototype.setCurrentStep = function(value) {
        if (value != null) {
          this._current = value;
          return this.setState("current_step", value);
        } else {
          this._current = this.getState("current_step");
          if (this._current === null || this._current === "null") {
            return this._current = 0;
          } else {
            return this._current = parseInt(this._current);
          }
        }
      };

      Tour.prototype.showNextStep = function() {
        var step;
        step = this.getStep(this._current);
        return this.showStep(step.next);
      };

      Tour.prototype.showPrevStep = function() {
        var step;
        step = this.getStep(this._current);
        return this.showStep(step.prev);
      };

      Tour.prototype._showPopover = function(step, i) {
        var content, nav, tip, position, this_;
        this_ = this;
        //.popover-fixed {
        // position: fixed;
        //}
        position = (step.position && step.position == 'fixed') ? ' popover-fixed' : '';
        content = "" + step.content + "
";
        nav = [];
        if (step.reflex)
        {
          $(step.element).on('click', function(e) {
            this_.hideStep(this_._current);
            if (step.next)
              this_._current = step.next;
            this_.showNextStep();
          });
        }
        if (step.prev >= 0) {
          nav.push("" + step.options.previous + "");
        }
        if (step.next >= 0) {
          nav.push("" + step.options.next + "");
        }
        content += nav.join(" | ");
        content += "" + step.options.end + "";
        $(step.element).popover({
          placement: step.placement,
          trigger: "manual",
          title: step.title,
          content: content,
          animation: step.animation,
          template: '

'
        }).popover("show");
        tip = $(step.element).data("popover").tip();
        this._reposition(tip);
        if (!step.position)
          return this._scrollIntoView(tip);
        tip.css('top', $(step.element).get(0).offsetHeight + 'px');
        return ;
      };

      Tour.prototype._reposition = function(tip) {
        var offsetBottom, offsetRight, tipOffset;
        tipOffset = tip.offset();
        offsetBottom = $(document).outerHeight() - tipOffset.top - $(tip).outerHeight();
        if (offsetBottom < 0) {
          tipOffset.top = tipOffset.top + offsetBottom;
        }
        offsetRight = $(document).outerWidth() - tipOffset.left - $(tip).outerWidth();
        if (offsetRight < 0) {
          tipOffset.left = tipOffset.left + offsetRight;
        }
        if (tipOffset.top < 0) {
          tipOffset.top = 0;
        }
        if (tipOffset.left < 0) {
          tipOffset.left = 0;
        }
        return tip.offset(tipOffset);
      };

      Tour.prototype._scrollIntoView = function(tip) {
        var tipRect;
        tipRect = tip.get(0).getBoundingClientRect();
        if (!(tipRect.top > 0 && tipRect.bottom < $(window).height() && tipRect.left > 0 && tipRect.right < $(window).width())) {
          return tip.get(0).scrollIntoView(true);
        }
      };

      return Tour;

    })();
    return window.Tour = Tour;
  })(jQuery, window);

}).call(this);
<|endoftext|>


<commit_before>var fs = require('fs');
var path = require('path');

var environmentVariables = [
    "WEBSITE_SITE_NAME",
    "WEBSITE_SKU",
    "WEBSITE_COMPUTE_MODE",
    "WEBSITE_HOSTNAME",
    "WEBSITE_INSTANCE_ID",
    "WEBSITE_NODE_DEFAULT_VERSION",
    "WEBSOCKET_CONCURRENT_REQUEST_LIMIT",
    "APPDATA",
    "TMP",
    "HOME",
    "SYSTEMDRIVE",
    "WEBJOBS_PATH",
    "WEBJOBS_NAME",
    "WEBJOBS_TYPE",
    "WEBJOBS_DATA_PATH",
    "WEBJOBS_RUN_ID",
    "WEBJOBS_SHUTDOWN_FILE",
    "WEBSITE_NODE_DEFAULT_VERSION",
    "WEBSITE_NPM_DEFAULT_VERSION"
]

module.exports = function (context, req, res) {
    context.log('function triggered');
    context.log(req);

    context.log('Environment Variables');
    environmentVariables
        .map(getEnvironmentVarible)
        .forEach(function (x) {
            context.log(x);
        });

    context.log('process.cwd()', process.cwd());
    context.log('__dirname', __dirname);

    var tempDir = process.env["TMP"];
    var filePath = path.join(tempDir, 'message.txt');
    var fileContents = 'Hellow Node.js_' + req.body;

    context.log("writing: ", fileContents);

    fs.writeFile(filePath, fileContents, (err) => {
        if (err) {
            throw err;
        }

        context.log("File is saved!");
        context.done();
    });
}

function getEnvironmentVarible(name) {
    return name + ": " + process.env[name];
}<commit_msg>Add custom response object.<commit_after>var fs = require('fs');
var path = require('path');

var environmentVariables = [
    "WEBSITE_SITE_NAME",
    "WEBSITE_SKU",
    "WEBSITE_COMPUTE_MODE",
    "WEBSITE_HOSTNAME",
    "WEBSITE_INSTANCE_ID",
    "WEBSITE_NODE_DEFAULT_VERSION",
    "WEBSOCKET_CONCURRENT_REQUEST_LIMIT",
    "APPDATA",
    "TMP",
    "HOME",
    "SYSTEMDRIVE",
    "WEBJOBS_PATH",
    "WEBJOBS_NAME",
    "WEBJOBS_TYPE",
    "WEBJOBS_DATA_PATH",
    "WEBJOBS_RUN_ID",
    "WEBJOBS_SHUTDOWN_FILE",
    "WEBSITE_NODE_DEFAULT_VERSION",
    "WEBSITE_NPM_DEFAULT_VERSION"
]

module.exports = function (context, req, res) {
    context.log('function triggered');
    context.log(req);

    context.log('Environment Variables');
    environmentVariables
        .map(getEnvironmentVarible)
        .forEach(function (x) {
            context.log(x);
        });

    context.log('process.cwd()', process.cwd());
    context.log('__dirname', __dirname);

    var tempDir = process.env["TMP"];
    var filePath = path.join(tempDir, 'message.txt');
    var fileContents = 'Hellow Node.js_' + req.body.message;

    context.log("writing: ", fileContents);

    fs.writeFile(filePath, fileContents, (err) => {
        if (err) {
            throw err;
        }

        context.log("File is saved!");
        context.res = {
            status: 200,
            body: {
                message: 'You successfully saved the file!'
            }
        };
        context.done();
    });
}

function getEnvironmentVarible(name) {
    return name + ": " + process.env[name];
}<|endoftext|>


<commit_before>'use strict';

/**
 * @ngdoc function
 * @name namsaiEditorApp.controller:RepomessageCtrl
 * @description
 * # RepomessageCtrl
 * Controller of the namsaiEditorApp
 */
angular.module('namsaiEditorApp')
  .controller('RepomessageCtrl', function ($scope,$http,API,$routeParams,localStorageService) {
    var repoMessage = localStorageService.get('repoMessage');
    var lastTimestamp;
    if(repoMessage){
      $scope.messageList = repoMessage.message;
      lastTimestamp = new Date(repoMessage.timestamp);
    }else{
      $scope.messageList = [];
    }
    var reply = function(input,callback){
      var url = API+'/v1/repos/'+$routeParams.repo+'/messages';
      $http({
        url: url,
        method: "POST",
        headers: {'Content-Type': 'application/x-www-form-urlencoded'},
        data: "input="+input
      }).then(function(response) {
        response.data.message.forEach(function(r){
          callback(r);
        })
      },function(response) {
        //console.error(response);
        callback(response.data.error.message);
      });
    }
    var getDateText = function(){
      var hour = date.getHours();
      var minute = +date.getMinutes();
      hour = (hour<10)?'0'+hour:hour;
      minute = (minute<10)?'0'+minute:minute;
      var out = ''+date.getDate()+'/'+(date.getMonth()+1)+'/'+date.getFullYear()+' '+hour+':'+minute;
      return out;
    }
    $scope.input = function(value){
      if(!lastTimestamp || (new Date() - lastTimestamp)/1000 > 300){
        var date = new Date();
        $scope.messageList.push({"type":"time","value":getDateText()});
      }
      $scope.messageList.push({"type":"user","value":value});
      $scope.inputText = '';
      reply(value,function(value){
        $scope.messageList.push({"type":"bot","value":value});
        localStorageService.set('repoMessage',{timestamp:new Date(),message:$scope.messageList});
      })
    }
  }).directive('myEnter', function () {
      return function (scope, element, attrs) {
          element.bind("keydown keypress", function (event) {
              if(event.which === 13) {
                  scope.$apply(function (){
                      scope.$eval(attrs.myEnter);
                  });
                event.preventDefault();
              }
          });
      };
  });
<commit_msg>Fix: crash on date undefined<commit_after>'use strict';

/**
 * @ngdoc function
 * @name namsaiEditorApp.controller:RepomessageCtrl
 * @description
 * # RepomessageCtrl
 * Controller of the namsaiEditorApp
 */
angular.module('namsaiEditorApp')
  .controller('RepomessageCtrl', function ($scope,$http,API,$routeParams,localStorageService) {
    var repoMessage = localStorageService.get('repoMessage');
    var lastTimestamp;
    if(repoMessage){
      $scope.messageList = repoMessage.message;
      lastTimestamp = new Date(repoMessage.timestamp);
    }else{
      $scope.messageList = [];
    }
    var reply = function(input,callback){
      var url = API+'/v1/repos/'+$routeParams.repo+'/messages';
      $http({
        url: url,
        method: "POST",
        headers: {'Content-Type': 'application/x-www-form-urlencoded'},
        data: "input="+input
      }).then(function(response) {
        response.data.message.forEach(function(r){
          callback(r);
        })
      },function(response) {
        //console.error(response);
        callback(response.data.error.message);
      });
    }
    var getDateText = function(){
      var date = new Date();
      var hour = date.getHours();
      var minute = +date.getMinutes();
      hour = (hour<10)?'0'+hour:hour;
      minute = (minute<10)?'0'+minute:minute;
      var out = ''+date.getDate()+'/'+(date.getMonth()+1)+'/'+date.getFullYear()+' '+hour+':'+minute;
      return out;
    }
    $scope.input = function(value){
      if(!lastTimestamp || (new Date() - lastTimestamp)/1000 > 300){
        $scope.messageList.push({"type":"time","value":getDateText()});
      }
      $scope.messageList.push({"type":"user","value":value});
      $scope.inputText = '';
      reply(value,function(value){
        $scope.messageList.push({"type":"bot","value":value});
        localStorageService.set('repoMessage',{timestamp:new Date(),message:$scope.messageList});
      })
    }
  }).directive('myEnter', function () {
      return function (scope, element, attrs) {
          element.bind("keydown keypress", function (event) {
              if(event.which === 13) {
                  scope.$apply(function (){
                      scope.$eval(attrs.myEnter);
                  });
                event.preventDefault();
              }
          });
      };
  });
<|endoftext|>


<commit_before>/*jslint indent: 2, node: true */
/*global require: false, process: false */

// parseCSVBill.js
//
// Parse the billing detail from Azure so we know what to charge our customers.
//
var path = require('path'),
  fs = require('fs'),
  parseCSV = require('../common/parseCSV.js'),
  argv = process.argv,
  argc = argv.length,
  verbose = false,
  echo = function () {
    if (verbose) {
      console.log.apply(null, arguments);
    }
  },
  trimQuotes = function (column) {
    "use strict";

    if (column.length > 1) {
      if (column[0] === column[column.length - 1] && column[0] === '"') {
        return trimQuotes(column.slice(1, -1));
      }
    }
    return column;
  },
  formatDollars = function (number) {
    "use strict";

    return "$" + (Math.round(number * 100) / 100) + " USD";
  },
  parseBillLine = function (line, n) {
    "use strict";

    var item = {};

    this.state = this.state || 0;
    this.csv = this.csv || {};
    this.section = this.section || "";
    this.labels = this.labels || [];

    switch (this.state) {
    case 0: // Looking for next section
      if (line.length === 1 && line[0] !== "") {
        echo("Found section: ", line[0]);
        this.section = line[0];
        this.csv[this.section] = [];
        this.state = 1;
      }
      break;
    case 1: // record labels
      echo("Recording Label: ", line);
      this.labels = line;
      this.state = 2;
      break;
    case 2: // record item
      if (this.labels.length !== line.length) {
        if (line.length !== 1) {
          console.log("ERROR: (line %s) Bill is not formatted correctly [%s]", n, line);
          this.state = 3;
        } else {
          this.state = 0;
        }
      } else {
        item = {};
        this.labels.forEach(function (label, i) {
          item[label] = trimQuotes(line[i]);
        });
        echo("Recording item: ", item);
        this.csv[this.section].push(item);
      }
      break;
    case 3: // ERROR state
      break;
    default:
      break;
    }
  },
  parseBill = function (data) {
    "use strict";

    var context = {};

    data = parseCSV(data);
    data.forEach(parseBillLine, context);

    if (context.state !== 3) {
      return context.csv;
    }

    return null;
  },
  subTotalBill = function (bill) {
    "use strict";

    bill.Subtotals = {};
    bill.Totals = {};

    bill["Daily Usage"].forEach(function (current) {
      var MeterName = current["Meter Name"],
        ConsumedQuantity = Number(current["Consumed Quantity"]),
        InstanceId = current["Instance Id"];

      echo("Accumulating Subtotal: ", InstanceId, MeterName, ConsumedQuantity);
      bill.Subtotals[InstanceId] = bill.Subtotals[InstanceId] || {};
      bill.Subtotals[InstanceId][MeterName] = bill.Subtotals[InstanceId][MeterName] || 0;
      bill.Subtotals[InstanceId][MeterName] += ConsumedQuantity;

      echo("Accumulating Total: ", MeterName, ConsumedQuantity);
      bill.Totals[MeterName] = bill.Totals[MeterName] || {};
      bill.Totals[MeterName].AggregateTotal = bill.Totals[MeterName].AggregateTotal || 0;
      bill.Totals[MeterName].AggregateTotal += ConsumedQuantity;
    });
  },
  totalBill = function (bill) {
    "use strict";

    bill.Statement.forEach(function (current) {
      var MeterName = current["Meter Name"],
        ConsumedQuantity = Number(current["Consumed Quantity"]),
        Cost = Number(current.Value.slice(1, -4));

      echo("Recording Total: ", MeterName, ConsumedQuantity, Cost);

      bill.Totals[MeterName] = bill.Totals[MeterName] || {};
      bill.Totals[MeterName].Total = ConsumedQuantity;
      bill.Totals[MeterName].Cost = Cost;
    });
  },
  calculateReport = function (bill) {
    "use strict";

    var InstanceId = "",
      AggregateCost = 0,
      MeterName = "",
      ConsumedQuantity = 0,
      TotalQuantity = 0,
      TotalCost = 0,
      Cost = 0;

    for (InstanceId in bill.Subtotals) {
      if (bill.Subtotals.hasOwnProperty(InstanceId)) {
        console.log("------------------------------------------------------------");
        console.log("Charges for " + InstanceId);
        AggregateCost = 0;

        for (MeterName in bill.Subtotals[InstanceId]) {
          if (bill.Subtotals[InstanceId].hasOwnProperty(MeterName)) {
            ConsumedQuantity = bill.Subtotals[InstanceId][MeterName];
            TotalQuantity = bill.Totals[MeterName].AggregateTotal;
            TotalCost = bill.Totals[MeterName].Cost;
            Cost = TotalCost * (ConsumedQuantity / TotalQuantity);
            AggregateCost += Cost;

            console.log("    " + MeterName + " @ " + ConsumedQuantity + "/" + TotalQuantity + " = " + formatDollars(Cost) + " (of " + formatDollars(TotalCost) + ")");
          }
        }

        console.log("    Aggregated Cost = " + formatDollars(AggregateCost));
      }
    }
  },
  main = function (argc, argv) {
    "use strict";

    var bill = {};

    if (argc !== 3) {
      console.log('usage: %s %s <filename>', argv[0], argv[1]);
    } else {
      fs.readFile(path.resolve(".", argv[2]), { 'encoding': "utf8" }, function (err, data) {
        if (err) {
          console.log('ERROR: failed to read file');
        } else {
          bill = parseBill(data);
          if (bill && bill.hasOwnProperty("Statement") && bill.hasOwnProperty("Daily Usage")) {
            subTotalBill(bill);
            totalBill(bill);
            calculateReport(bill);
          }
        }
      });
    }
  };

main(argc, argv);
<commit_msg>account for the , in "$1,024 USD"<commit_after>/*jslint indent: 2, node: true */
/*global require: false, process: false */

// parseCSVBill.js
//
// Parse the billing detail from Azure so we know what to charge our customers.
//
var path = require('path'),
  fs = require('fs'),
  parseCSV = require('../common/parseCSV.js'),
  argv = process.argv,
  argc = argv.length,
  verbose = false,
  echo = function () {
    if (verbose) {
      console.log.apply(null, arguments);
    }
  },
  trimQuotes = function (column) {
    "use strict";

    if (column.length > 1) {
      if (column[0] === column[column.length - 1] && column[0] === '"') {
        return trimQuotes(column.slice(1, -1));
      }
    }
    return column;
  },
  formatDollars = function (number) {
    "use strict";

    return "$" + (Math.round(number * 100) / 100) + " USD";
  },
  parseBillLine = function (line, n) {
    "use strict";

    var item = {};

    this.state = this.state || 0;
    this.csv = this.csv || {};
    this.section = this.section || "";
    this.labels = this.labels || [];

    switch (this.state) {
    case 0: // Looking for next section
      if (line.length === 1 && line[0] !== "") {
        echo("Found section: ", line[0]);
        this.section = line[0];
        this.csv[this.section] = [];
        this.state = 1;
      }
      break;
    case 1: // record labels
      echo("Recording Label: ", line);
      this.labels = line;
      this.state = 2;
      break;
    case 2: // record item
      if (this.labels.length !== line.length) {
        if (line.length !== 1) {
          console.log("ERROR: (line %s) Bill is not formatted correctly [%s]", n, line);
          this.state = 3;
        } else {
          this.state = 0;
        }
      } else {
        item = {};
        this.labels.forEach(function (label, i) {
          item[label] = trimQuotes(line[i]);
        });
        echo("Recording item: ", item);
        this.csv[this.section].push(item);
      }
      break;
    case 3: // ERROR state
      break;
    default:
      break;
    }
  },
  parseBill = function (data) {
    "use strict";

    var context = {};

    data = parseCSV(data);
    data.forEach(parseBillLine, context);

    if (context.state !== 3) {
      return context.csv;
    }

    return null;
  },
  subTotalBill = function (bill) {
    "use strict";

    bill.Subtotals = {};
    bill.Totals = {};

    bill["Daily Usage"].forEach(function (current) {
      var MeterName = current["Meter Name"],
        ConsumedQuantity = Number(current["Consumed Quantity"]),
        InstanceId = current["Instance Id"];

      echo("Accumulating Subtotal: ", InstanceId, MeterName, ConsumedQuantity);
      bill.Subtotals[InstanceId] = bill.Subtotals[InstanceId] || {};
      bill.Subtotals[InstanceId][MeterName] = bill.Subtotals[InstanceId][MeterName] || 0;
      bill.Subtotals[InstanceId][MeterName] += ConsumedQuantity;

      echo("Accumulating Total: ", MeterName, ConsumedQuantity);
      bill.Totals[MeterName] = bill.Totals[MeterName] || {};
      bill.Totals[MeterName].AggregateTotal = bill.Totals[MeterName].AggregateTotal || 0;
      bill.Totals[MeterName].AggregateTotal += ConsumedQuantity;
    });
  },
  totalBill = function (bill) {
    "use strict";

    bill.Statement.forEach(function (current) {
      var MeterName = current["Meter Name"],
        ConsumedQuantity = Number(current["Consumed Quantity"]),
        Cost = Number(current.Value.slice(1, -4).replace(/\,/g, ""));

      echo("Recording Total: ", MeterName, ConsumedQuantity, Cost);

      bill.Totals[MeterName] = bill.Totals[MeterName] || {};
      bill.Totals[MeterName].Total = ConsumedQuantity;
      bill.Totals[MeterName].Cost = Cost;
    });
  },
  calculateReport = function (bill) {
    "use strict";

    var InstanceId = "",
      AggregateCost = 0,
      MeterName = "",
      ConsumedQuantity = 0,
      TotalQuantity = 0,
      TotalCost = 0,
      Cost = 0;

    for (InstanceId in bill.Subtotals) {
      if (bill.Subtotals.hasOwnProperty(InstanceId)) {
        console.log("------------------------------------------------------------");
        console.log("Charges for " + InstanceId);
        AggregateCost = 0;

        for (MeterName in bill.Subtotals[InstanceId]) {
          if (bill.Subtotals[InstanceId].hasOwnProperty(MeterName)) {
            ConsumedQuantity = bill.Subtotals[InstanceId][MeterName];
            TotalQuantity = bill.Totals[MeterName].AggregateTotal;
            TotalCost = bill.Totals[MeterName].Cost;
            Cost = TotalCost * (ConsumedQuantity / TotalQuantity);
            AggregateCost += Cost;

            console.log("    " + MeterName + " @ " + ConsumedQuantity + "/" + TotalQuantity + " = " + formatDollars(Cost) + " (of " + formatDollars(TotalCost) + ")");
          }
        }

        console.log("    Aggregated Cost = " + formatDollars(AggregateCost));
      }
    }
  },
  main = function (argc, argv) {
    "use strict";

    var bill = {};

    if (argc !== 3) {
      console.log('usage: %s %s <filename>', argv[0], argv[1]);
    } else {
      fs.readFile(path.resolve(".", argv[2]), { 'encoding': "utf8" }, function (err, data) {
        if (err) {
          console.log('ERROR: failed to read file');
        } else {
          bill = parseBill(data);
          if (bill && bill.hasOwnProperty("Statement") && bill.hasOwnProperty("Daily Usage")) {
            subTotalBill(bill);
            totalBill(bill);
            calculateReport(bill);
          }
        }
      });
    }
  };

main(argc, argv);
<|endoftext|>


<commit_before>'use strict';

/**
 * @ngdoc directive
 * @name grafterizerApp.directive:previewTable
 * @description
 * # previewTable
 */
angular.module('grafterizerApp')
.directive('previewTable', function($q, $mdToast, $rootScope) {

  var paginationSize = 100;

  return {
    template: '

\u2205

',
    restrict: 'E',
    scope: {
      data: '=ngModel',
      loadMore: '=ngLoadMore'
    },
    link: function postLink(scope, element, attrs) {
      scope.gridOptions = {
        data:  null,
        columnDefs: [],
        headerRowHeight: 82,
        rowHeight: 38,
        showHeader: !attrs.hasOwnProperty('hideHeaders'),
        exporterMenuCsv: true,
        exporterMenuPdf: false,
        enableGridMenu: true,
        enableMinHeightCheck: false,
        infiniteScrollUp: false,
        infiniteScrollDown: !!scope.loadMore,
        onRegisterApi: function(gridApi) {
          scope.gridApi = gridApi;

          if (scope.loadMore) {
            gridApi.infiniteScroll.on.needLoadMoreData(scope, scope.getDataDown);
          }

        }

      };

      scope.getDataDown = function() {
        scope.gridApi.infiniteScroll.saveScrollPercentage();
        var promise = $q.defer();
        scope.loadMore(function(err, data) {
          if (err) {
            scope.gridApi.infiniteScroll.dataLoaded(false, false);
            promise.reject();
            return;
          }

          if (!data.hasOwnProperty(':rows') || !data[':rows'].length) {
            scope.gridApi.infiniteScroll.dataLoaded(false, false);
            promise.resolve();
            return;
          }

          scope.gridOptions.data = scope.gridOptions.data.concat(data[':rows']);
          scope.gridApi.infiniteScroll.dataLoaded(
            false, data[':rows'].length >= paginationSize);
          promise.resolve();
        });

        return promise.promise;
      };

      scope.$watch('data', function() {
        var data = scope.data;
        if (!data || !data.hasOwnProperty(':rows')) {
          scope.gridOptions.data = [];

          if (scope.gridApi) {
            scope.gridApi.infiniteScroll.dataLoaded(false, false);
          }

          return;
        }

        var widths = {};
        var rawWidths = {};

        _.each(data[':column-names'], function(f) {
          if (f && (typeof f.length !== 'undefined')) {
            // the header size is 3 times more important
            widths[f] = f.length * 3;
          }
        });

        var rows = data[':rows'];
        var largest = 0;

        {
          var i;
          var key;
          var irow;
          var w;
          var maxIter = Math.min(10, rows.length);

          for (i = 0; i < maxIter; ++i) {
            for (key in rows[i]) {
              irow = rows[i][key];
              w = widths[key];

              if (w) {
                widths[key] += ('' + irow).length;
              }
            }
          }

          var total = 0;
          for (key in widths) {
            widths[key] /= (maxIter + 3);
            rawWidths[key] = widths[key];
            total += widths[key];
          }

          for (key in widths) {
            widths[key] = w = widths[key] / total;
            if (w > largest) {
              largest = w;
            }
          }
        }

        var nbEmptyColumnsFound = 0;
        var columnNamesSet = {};

        scope.gridOptions.columnDefs =
          _.map(data[':column-names'], function(f) {
            if (f === null || f === undefined) {
              f = 'EMPTY COLUMN HEADER';
              ++nbEmptyColumnsFound;
            }

          var preventMultipleWarning = false;
          while (columnNamesSet.hasOwnProperty(f)) {
            if (!preventMultipleWarning && f !== 'EMPTY COLUMN HEADER') {
              $mdToast.show(
                $mdToast.simple()
                .content('Warning: one or more column headers are identical. That may cause unexpected errors.')
                .position('bottom right')
                .hideDelay(6000)
              );
              preventMultipleWarning = true;
            }
            f = f + Math.floor(Math.random() * 10000);
          }

          columnNamesSet[f] = true;

            var w = widths[f];
            var width = w === largest || isNaN(w) ? '*' : Math.floor(w * 100) + '%';
            var minWidth = isNaN(rawWidths[f]) ? 200 : Math.min(80 + rawWidths[f] * 8, 200);
            var colNameString = f[0] === ':' ? f.substring(1) : f;
            return {
              name: '' + f,
              displayName: colNameString,
              width: width,
              minWidth: minWidth,
              cellTooltip: true
            };
          });

        if (nbEmptyColumnsFound > 0) {
          $mdToast.show(
            $mdToast.simple()
            .content('Warning: ' + nbEmptyColumnsFound + ' column header' +
              (nbEmptyColumnsFound > 1 ? 's' : '') +
              ' are empty. This may cause unexpected errors - please correct your transformation! ')
            .position('bottom right')
            .hideDelay(6000)
          );
        }

        if (scope.gridApi) {
          scope.gridApi.infiniteScroll.dataLoaded(false, rows.length >= paginationSize);
        }

        $rootScope.colnames = function() {
            var i;
            var namesArray = [];
            for (i = 0; i < scope.gridOptions.columnDefs.length; ++i) {
                var colname = {
                  id: i,
                  value: scope.gridOptions.columnDefs[i].displayName
                };
                namesArray.push(colname);
            }
            return namesArray;
        };

        scope.gridOptions.data = rows;
      });
    }
  };
});
<commit_msg>[BugFix] Workaround for UI-Grid and table keys containing paranthesis<commit_after>'use strict';

/**
 * @ngdoc directive
 * @name grafterizerApp.directive:previewTable
 * @description
 * # previewTable
 */
angular.module('grafterizerApp')
.directive('previewTable', function($q, $mdToast, $rootScope) {

  var paginationSize = 100;

  return {
    template: '

\u2205

',
    restrict: 'E',
    scope: {
      data: '=ngModel',
      loadMore: '=ngLoadMore'
    },
    link: function postLink(scope, element, attrs) {
      scope.gridOptions = {
        data:  null,
        columnDefs: [],
        headerRowHeight: 82,
        rowHeight: 38,
        showHeader: !attrs.hasOwnProperty('hideHeaders'),
        exporterMenuCsv: true,
        exporterMenuPdf: false,
        enableGridMenu: true,
        enableMinHeightCheck: false,
        infiniteScrollUp: false,
        infiniteScrollDown: !!scope.loadMore,
        onRegisterApi: function(gridApi) {
          scope.gridApi = gridApi;

          if (scope.loadMore) {
            gridApi.infiniteScroll.on.needLoadMoreData(scope, scope.getDataDown);
          }

        }

      };

      scope.getDataDown = function() {
        scope.gridApi.infiniteScroll.saveScrollPercentage();
        var promise = $q.defer();
        scope.loadMore(function(err, data) {
          if (err) {
            scope.gridApi.infiniteScroll.dataLoaded(false, false);
            promise.reject();
            return;
          }

          if (!data.hasOwnProperty(':rows') || !data[':rows'].length) {
            scope.gridApi.infiniteScroll.dataLoaded(false, false);
            promise.resolve();
            return;
          }

          scope.gridOptions.data = scope.gridOptions.data.concat(data[':rows']);
          scope.gridApi.infiniteScroll.dataLoaded(
            false, data[':rows'].length >= paginationSize);
          promise.resolve();
        });

        return promise.promise;
      };

      scope.$watch('data', function() {
        var data = scope.data;
        if (!data || !data.hasOwnProperty(':rows')) {
          scope.gridOptions.data = [];

          if (scope.gridApi) {
            scope.gridApi.infiniteScroll.dataLoaded(false, false);
          }

          return;
        }

        var widths = {};
        var rawWidths = {};

        _.each(data[':column-names'], function(f) {
          if (f && (typeof f.length !== 'undefined')) {
            // the header size is 3 times more important
            widths[f] = f.length * 3;
          }
        });

        var rows = data[':rows'];
        var largest = 0;

        {
          var i;
          var key;
          var irow;
          var w;
          var maxIter = Math.min(10, rows.length);

          for (i = 0; i < maxIter; ++i) {
            for (key in rows[i]) {
              irow = rows[i][key];
              w = widths[key];

              if (w) {
                widths[key] += ('' + irow).length;
              }
            }
          }

          var total = 0;
          for (key in widths) {
            widths[key] /= (maxIter + 3);
            rawWidths[key] = widths[key];
            total += widths[key];
          }

          for (key in widths) {
            widths[key] = w = widths[key] / total;
            if (w > largest) {
              largest = w;
            }
          }
        }

        var nbEmptyColumnsFound = 0;
        var columnNamesSet = {};

        scope.gridOptions.columnDefs =
          _.map(data[':column-names'], function(f) {
            if (f === null || f === undefined) {
              f = 'EMPTY COLUMN HEADER';
              ++nbEmptyColumnsFound;
            }

          var preventMultipleWarning = false;
          while (columnNamesSet.hasOwnProperty(f)) {
            if (!preventMultipleWarning && f !== 'EMPTY COLUMN HEADER') {
              $mdToast.show(
                $mdToast.simple()
                .content('Warning: one or more column headers are identical. That may cause unexpected errors.')
                .position('bottom right')
                .hideDelay(6000)
              );
              preventMultipleWarning = true;
            }
            f = f + Math.floor(Math.random() * 10000);
          }

          columnNamesSet[f] = true;

            var w = widths[f];
            var width = w === largest || isNaN(w) ? '*' : Math.floor(w * 100) + '%';
            var minWidth = isNaN(rawWidths[f]) ? 200 : Math.min(80 + rawWidths[f] * 8, 200);
            var colNameString = f[0] === ':' ? f.substring(1) : f;
            return {
              name: window.btoa('' + f),
              displayName: colNameString,
              width: width,
              minWidth: minWidth,
              cellTooltip: true
            };
          });

        if (nbEmptyColumnsFound > 0) {
          $mdToast.show(
            $mdToast.simple()
            .content('Warning: ' + nbEmptyColumnsFound + ' column header' +
              (nbEmptyColumnsFound > 1 ? 's' : '') +
              ' are empty. This may cause unexpected errors - please correct your transformation! ')
            .position('bottom right')
            .hideDelay(6000)
          );
        }

        if (scope.gridApi) {
          scope.gridApi.infiniteScroll.dataLoaded(false, rows.length >= paginationSize);
        }

        $rootScope.colnames = function() {
            var i;
            var namesArray = [];
            for (i = 0; i < scope.gridOptions.columnDefs.length; ++i) {
                var colname = {
                  id: i,
                  value: scope.gridOptions.columnDefs[i].displayName
                };
                namesArray.push(colname);
            }
            return namesArray;
        };

        // Ui-Grid has a bug with keys containing paranthesis and maybe other symbols
        // Workaround: convert the keys to base64
        var btoaData = [];

        for (i = 0; i < rows.length; ++i) {
          var tuple = {};
          for (key in rows[i]) {
            tuple[window.btoa(key)] = rows[i][key];
          }
          btoaData.push(tuple);
        }

        scope.gridOptions.data = btoaData;
      });
    }
  };
});
<|endoftext|>


<commit_before>'use strict';

goog.require('cgAdmin.homeModule');

goog.require('cgAdmin.CommunicationException');

goog.require('cgAdmin.NotFoundException');

goog.provide('cgAdmin.ContentService');

/**
 * @constructor
 * @ngInject
 */
cgAdmin.ContentService = function($http, $resource) {

  var root = 'http://127.0.0.1:19836/integrationtest';

  var CopybeanResource = $resource(root + '/copybeans/:id', null, {
    'update': {method: 'PUT'}
  });

  var CopybeanTypeResource = $resource(root + '/copybeans/types/:id', null, {
    'update': {method: 'PUT'}
  });

  var defaultErrorCallback = function(errorResponse) {
    console.log(errorResponse);
    if (!errorResponse.data && !errorResponse.status) {
      throw new cgAdmin.CommunicationException(errorResponse);
    }
    if (errorResponse.status === 404) {
      throw new cgAdmin.NotFoundException(errorResponse);
    }
    throw errorResponse.data;
  };

  function defaultErrorHandler(errorCallback) {
    if (errorCallback) {
      return errorCallback;
    } else {
      return defaultErrorCallback;
    }
  }

  this.getTypesSummary = function(successFunc, errorFunc) {
    CopybeanTypeResource.query({'fields': 'id,displayName,cardinality'}, successFunc, defaultErrorHandler(errorFunc));
  };

  this.getTypesByIds = function(ids, successFunc, errorFunc) {
    CopybeanTypeResource.query({'id~': ids}, successFunc, defaultErrorHandler(errorFunc));
  };

  this.getType = function(id, successFunc, errorFunc) {
    CopybeanTypeResource.get({'id': id}, successFunc, defaultErrorHandler(errorFunc));
  };

  this.getBeansByType = function(typeId, successFunc, errorFunc) {
    CopybeanResource.query({'enforcedTypeIds': typeId}, successFunc, defaultErrorHandler(errorFunc));
  };

  this.getMetaBean = function(successFunc, errorFunc) {
    CopybeanResource.query({
      'enforcedTypeIds': 'copygrinderAdminMetatype',
      'fields': 'content'
    }, successFunc, defaultErrorHandler(errorFunc));
  };

  this.getBean = function(id, successFunc, errorFunc) {
    CopybeanResource.get({'id': id}, successFunc, defaultErrorHandler(errorFunc));
  };

  this.editBean = function(bean, successFunc, errorFunc) {
    var newBean = angular.copy(bean);
    delete newBean.id;
    delete newBean.names;
    CopybeanResource.update({'id': bean.id}, newBean, successFunc, defaultErrorHandler(errorFunc));
  };

  this.saveBean = function(bean, successFunc, errorFunc) {
    CopybeanResource.save(bean, successFunc, defaultErrorHandler(errorFunc));
  };

  this.editType = function(type, successFunc, errorFunc) {
    CopybeanTypeResource.update({'id': type.id}, type, successFunc, defaultErrorHandler(errorFunc));
  };

  this.saveType = function(type, successFunc, errorFunc) {
    CopybeanTypeResource.save(type, successFunc, defaultErrorHandler(errorFunc));
  };

  this.deleteBean = function(bean, successFunc, errorFunc) {
    CopybeanResource.remove({'id': bean.id}, successFunc, defaultErrorHandler(errorFunc));
  };

  this.deleteType = function(type, successFunc, errorFunc) {
    CopybeanTypeResource.remove({'id': type.id}, successFunc, defaultErrorHandler(errorFunc));
  };

};

cgAdmin.homeModule.service('contentService', cgAdmin.ContentService);
<commit_msg>Filtered out predefined types.<commit_after>'use strict';

goog.require('cgAdmin.homeModule');

goog.require('cgAdmin.CommunicationException');

goog.require('cgAdmin.NotFoundException');

goog.provide('cgAdmin.ContentService');

/**
 * @constructor
 * @ngInject
 */
cgAdmin.ContentService = function($http, $resource) {

  var root = 'http://127.0.0.1:19836/integrationtest';

  var CopybeanResource = $resource(root + '/copybeans/:id', null, {
    'update': {method: 'PUT'}
  });

  var CopybeanTypeResource = $resource(root + '/copybeans/types/:id', null, {
    'update': {method: 'PUT'}
  });

  var defaultErrorCallback = function(errorResponse) {
    console.log(errorResponse);
    if (!errorResponse.data && !errorResponse.status) {
      throw new cgAdmin.CommunicationException(errorResponse);
    }
    if (errorResponse.status === 404) {
      throw new cgAdmin.NotFoundException(errorResponse);
    }
    throw errorResponse.data;
  };

  function defaultErrorHandler(errorCallback) {
    if (errorCallback) {
      return errorCallback;
    } else {
      return defaultErrorCallback;
    }
  }

  this.getTypesSummary = function(successFunc, errorFunc) {
    CopybeanTypeResource.query({
      'fields': 'id,displayName,cardinality',
      'tags!': 'PREDEFINED'
    }, successFunc, defaultErrorHandler(errorFunc));
  };

  this.getTypesByIds = function(ids, successFunc, errorFunc) {
    CopybeanTypeResource.query({'id~': ids}, successFunc, defaultErrorHandler(errorFunc));
  };

  this.getType = function(id, successFunc, errorFunc) {
    CopybeanTypeResource.get({'id': id}, successFunc, defaultErrorHandler(errorFunc));
  };

  this.getBeansByType = function(typeId, successFunc, errorFunc) {
    CopybeanResource.query({'enforcedTypeIds': typeId}, successFunc, defaultErrorHandler(errorFunc));
  };

  this.getMetaBean = function(successFunc, errorFunc) {
    CopybeanResource.query({
      'enforcedTypeIds': 'copygrinderAdminMetatype',
      'fields': 'content'
    }, successFunc, defaultErrorHandler(errorFunc));
  };

  this.getBean = function(id, successFunc, errorFunc) {
    CopybeanResource.get({'id': id}, successFunc, defaultErrorHandler(errorFunc));
  };

  this.editBean = function(bean, successFunc, errorFunc) {
    var newBean = angular.copy(bean);
    delete newBean.id;
    delete newBean.names;
    CopybeanResource.update({'id': bean.id}, newBean, successFunc, defaultErrorHandler(errorFunc));
  };

  this.saveBean = function(bean, successFunc, errorFunc) {
    CopybeanResource.save(bean, successFunc, defaultErrorHandler(errorFunc));
  };

  this.editType = function(type, successFunc, errorFunc) {
    CopybeanTypeResource.update({'id': type.id}, type, successFunc, defaultErrorHandler(errorFunc));
  };

  this.saveType = function(type, successFunc, errorFunc) {
    CopybeanTypeResource.save(type, successFunc, defaultErrorHandler(errorFunc));
  };

  this.deleteBean = function(bean, successFunc, errorFunc) {
    CopybeanResource.remove({'id': bean.id}, successFunc, defaultErrorHandler(errorFunc));
  };

  this.deleteType = function(type, successFunc, errorFunc) {
    CopybeanTypeResource.remove({'id': type.id}, successFunc, defaultErrorHandler(errorFunc));
  };

};

cgAdmin.homeModule.service('contentService', cgAdmin.ContentService);
<|endoftext|>